北大ACM校赛C15I:The New MindSwitcher

来源:互联网 发布:金融网络销售工作内容 编辑:程序博客网 时间:2024/06/12 23:51

题意:Professor Farnsworth and Amy Wong create The New MindSwitcher! A The New MindSwitcher allows two users to switch minds with each other without any limits. There are N people have already tried it, and each of them may have other’s mind now. Obviously, it is a great invention, but it also leads to trouble. People who do evil can use it to escape from punishment, or even set others up. When this realization hit, Professor Farnsworth decides to return every mind back to its original body.
There are a lot of The New MindSwitchers, which means in each turn, any number of pairs of people can switch minds. However, no one can switch minds with himself/herself or with more than one people at the same time. To avoid getting into bigger trouble, it is forbidden to introduce new people who did not have used The New MindSwitcher. And most importantly, to finish this work as soon as possible, Professor Farnsworth wants to arrange this process to minimize the number of turns.

大致就是讲N个人,每个人的思想可能在其他人手里,且一个人只能有一个思想,每个时刻可以进行置换——任意交换两个人的思想,每个人每个时刻只能被交换一次,求最少置换次数和方案。这就相当于一个所有点出度和入度都为1的有向图,我们先求出图中所有的环,每个环就是一个置换群,因为要次数最少,所以环与环之间不会存在交换(当然在不影响次数的前提下也可以换,忽略这种情况)。我们知道对于一个个数>2的置换群,只需要2步操作就可以完成,一步是让所有的点构成互相指向的点对(或者自己指向自己),另一步点对之间交换一下就可以了,所以答案最多是2。接下来我们构造一下方案,从环中的一个点开始,逐步地找可以和它互相指向的点(有且仅有一个),中间实时地记录一下它拥有的思想的点和拥有它的思想的点就可以了,对于环的个数为1和2时要特判。

#include<iostream>#include<vector>#include<cstring>#include<cstdio>#include<map>#include<stack> using namespace std;const int maxn=10000+10;int pre[maxn],low[maxn],sccno[maxn],n,scc_cnt,tot,has[maxn],belong[maxn],vis[maxn],dfs_clock;map<string,int> mp;char s1[20],s2[20],out[maxn][20];vector<int> scc[maxn];vector<int> g[maxn];struct node{  int x,y;};vector<node> ans[20];stack<int> S; void dfs(int p){  pre[p]=low[p]=++dfs_clock;  S.push(p);   for(int i=0;i<g[p].size();i++)  {    int v=g[p][i];    if(!pre[v])    {      dfs(v);      low[p]=min(low[p],low[v]);    }    else if(!sccno[v]) low[p]=min(low[p],pre[v]);  }  if(low[p]==pre[p])  {    scc_cnt++;    int x=S.top();    while(1)    {      sccno[x]=scc_cnt;      S.pop();      scc[scc_cnt].push_back(x);      if(x==p) break;      x=S.top();    }  }}void find_scc(){  for(int i=1;i<=n;i++)    if(!sccno[i]) dfs(i);}bool check(int j){  for(int i=0;i<scc[j].size();i++)  {    int u=scc[j][i],v=has[u];    if(has[u]==u) continue;    if(has[v]!=u) return false;  }  return true;}int main(){  scanf("%d",&n);  for(int i=1;i<=n;i++)  {    scanf("%s%s",&s1,&s2);    int u=mp[s1];    if(!u)     {      u=mp[s1]=++tot;      int l=strlen(s1);      for(int j=0;j<l;j++)        out[tot][j]=s1[j];    }    int v=mp[s2];    if(!v)     {      v=mp[s2]=++tot;      int l=strlen(s2);      for(int j=0;j<l;j++)        out[tot][j]=s2[j];    }    g[u].push_back(v);    has[u]=v;belong[v]=u;  }  find_scc();int maxi=0;  for(int i=1;i<=scc_cnt;i++)  {    int tt;    if(scc[i].size()==1)     {       maxi=max(maxi,0);       continue;    }    if(scc[i].size()==2)    {      tt=1;      ans[tt].push_back((node){scc[i][0],scc[i][1]});      maxi=max(maxi,1);      continue;    }    int u=scc[i][0];    while(!check(i))    {      //cout<<u<<endl;      int v=has[u];      int k=belong[u];      swap(has[v],has[k]);      ans[1].push_back((node){v,k});      u=k;    }    for(int j=0;j<scc[i].size();j++)    {      int u=scc[i][j],v=has[u];      if(has[u]==u)      {        vis[u]=1;        continue;      }      if(vis[u]) continue;      ans[2].push_back((node){u,v});      vis[u]=vis[v]=true;      swap(has[u],has[v]);    }    maxi=max(maxi,2);  }  printf("%d\n",maxi);  for(int i=1;i<=maxi;i++)  {    printf("%d\n",ans[i].size());    for(int j=0;j<ans[i].size();j++)    {      int u=ans[i][j].x,v=ans[i][j].y;      printf("%s %s\n",out[u],out[v]);    }  }  return 0;}
0 0