hdu 4685(强连通分量+二分图)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685

题意:n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能的结婚对象,

必须保证王子与任意这些对象中的一个结婚,都不会影响到剩余的王子的配对数,也就是不能让剩余的王子中突然有一个人没婚可结了。

分析:这题是poj 1904的加强版,poj 1904的王子和公主数是相等的,这里可以不等,且poj 1904给出了一个初始完美匹配,但是这题就要自己求。

所以只要求出完美匹配之后,就和poj 1904的做法就完全相同了,这里就不在赘述了,可以参考:http://www.cnblogs.com/frog112111/p/3384261.html

那么怎么求出完美匹配呢?一开始我用多重匹配的匈牙利算法来做,但是怎么做都不对.......看了题解才恍然大悟=_=

先说几个坑,这题有点奇怪,就是所有王子都可以争着和同一个公主结婚,只要该王子喜欢该公主,感觉公主有点悲哀呀........

比如:2 2

        1 1

        1 1

 

      

输出的答案是:1 1   而不是  1 1

                    1 1             0        

这里就是和poj 1904有点不一样的地方,坑了我好久.........

求完美匹配:

先对原图用匈牙利算法做一遍二分图匹配,但是还有可能剩余一些人还没匹配,只要虚拟出一些节点来匹配剩余的点就行了

假设王子有剩下的,那么每个剩下的王子就连一个虚拟的公主,这个公主被所有的王子都喜欢。

假设公主有剩下的,那么每个剩下的公主就连一个虚拟的王子,这个王子喜欢所有的公主

这样就构成完美匹配了,接下来就是和poj 1904一样了。

注意:虽然n和m才500,但是数组要开到2000才能过,可能是剩余太多顶点没匹配,所以要虚拟出比较多的顶点吧,我只开到1500,wa到死=_=

还有就是一些细节没处理好也贡献了好多wa,做了一天.........快奔溃了,最后参考别人的代码改来改去才AC,好艰辛,不过最终能过也算安慰了

果然想问题还是不够周全,不够细心

大三了都,哎,弱成一坨翔了~

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=2000;
  6 const int M=1000000+3000;
  7 struct EDGE{
  8     int v,next;
  9 }edge[M];
 10 int first[N],low[N],dfn[N],sta[M],belong[N];
 11 int ans[N],match[N],flag[N];
 12 bool instack[N],vis[N];
 13 int n,m,g,cnt,top,scc,maxn;
 14 int Scan()      //输入外挂
 15 {
 16     int res=0,ch,flag=0;
 17     if((ch=getchar())=='-')
 18         flag=1;
 19     else if(ch>='0'&&ch<='9')
 20         res=ch-'0';
 21     while((ch=getchar())>='0'&&ch<='9')
 22         res=res*10+ch-'0';
 23     return flag?-res:res;
 24 }
 25 void Out(int a)    //输出外挂
 26 {
 27     if(a>9)
 28         Out(a/10);
 29     putchar(a%10+'0');
 30 }
 31 void AddEdge(int u,int v)
 32 {
 33     edge[g].v=v;
 34     edge[g].next=first[u];
 35     first[u]=g++;
 36 }
 37 int min(int a,int b)
 38 {
 39     return a<b?a:b;
 40 }
 41 int max(int a,int b)
 42 {
 43     return a>b?a:b;
 44 }
 45 void init()
 46 {
 47     g=cnt=top=scc=0;
 48     memset(first,-1,sizeof(first));
 49     memset(dfn,0,sizeof(dfn));
 50     memset(instack,false,sizeof(instack));
 51     memset(flag,0,sizeof(flag));
 52     //scanf("%d%d",&n,&m);
 53     n=Scan();
 54     m=Scan();
 55     maxn=max(n,m);    //王子和公主数可能不同,为了建图方便去较大者,王子编号1--maxn,公主编号maxn+1--2*maxn
 56 }
 57 bool dfs(int u)
 58 {
 59     int i,v;
 60     for(i=first[u];i!=-1;i=edge[i].next)
 61     {
 62         v=edge[i].v;
 63         if(!vis[v])
 64         {
 65             vis[v]=true;
 66             if(match[v]==0||dfs(match[v]))
 67             {
 68                 match[v]=u;
 69                 flag[u]=v;
 70                 return true;
 71             }
 72         }
 73     }
 74     return false;
 75 }
 76 void xiong()    //二分匹配
 77 {
 78     int i;
 79     memset(match,0,sizeof(match));
 80     for(i=1;i<=maxn;i++)
 81     {
 82         memset(vis,false,sizeof(vis));
 83         dfs(i);
 84     }
 85 }
 86 void Tarjan(int u)     //求强连通分量
 87 {
 88     int i,v;
 89     low[u]=dfn[u]=++cnt;
 90     sta[++top]=u;
 91     instack[u]=true;
 92     for(i=first[u];i!=-1;i=edge[i].next)
 93     {
 94         v=edge[i].v;
 95         if(!dfn[v])
 96         {
 97             Tarjan(v);
 98             low[u]=min(low[u],low[v]);
 99         }
100         else if(instack[v])
101             low[u]=min(low[u],dfn[v]);
102     }
103     if(low[u]==dfn[u])
104     {
105         scc++;
106         while(1)
107         {
108             v=sta[top--];
109             instack[v]=false;
110             belong[v]=scc;
111             if(u==v)
112                 break;
113         }
114     }
115 }
116 void build()
117 {
118     int i,k,v,j;
119     for(i=1;i<=n;i++)
120     {
121     //    scanf("%d",&k);
122         k=Scan();
123         while(k--)
124         {
125         //    scanf("%d",&v);
126             v=Scan();
127             AddEdge(i,v+maxn);    //王子和喜欢的公主之间连边
128         }
129     }
130 
131     xiong();   //做一次二分匹配
132 
133     int all=2*maxn;
134     for(i=1;i<=maxn;i++)    //为剩余王子匹配虚拟公主
135     {
136         if(!flag[i])
137         {
138             all++;
139             for(j=1;j<=maxn;j++)  //所有王子都喜欢该虚拟公主
140                 AddEdge(j,all);
141             match[all]=i;
142             flag[i]=all;
143         }
144     }
145 
146     for(i=maxn+1;i<=2*maxn;i++)    //为剩余公主匹配虚拟王子
147     {
148         if(!match[i])
149         {
150             all++;
151             for(j=maxn+1;j<=2*maxn;j++)   //该虚拟王子喜欢所有公主
152                 AddEdge(all,j);
153             flag[all]=i;
154             match[i]=all;
155         }
156     }
157     for(i=1;i<=all;i++)    //所有与王子匹配的公主建一条边连向王子
158     {
159         if(flag[i])
160             AddEdge(flag[i],i);
161     }
162 }
163 void solve()
164 {
165     int i,u,v;
166     for(i=1;i<=maxn;i++)   //求强连通分量
167         if(!dfn[i])
168             Tarjan(i);
169 
170     for(u=1;u<=n;u++)  //枚举所有王子
171     {
172         int count=0;
173         for(i=first[u];i!=-1;i=edge[i].next)
174         {
175             v=edge[i].v;
176             if(belong[u]==belong[v])    //王子与公主同在一个强连通分量
177             {
178                 if(v-maxn>m)
179                     continue;
180                 ans[count++]=v-maxn;
181             }
182         }
183         sort(ans,ans+count);
184     //    printf("%d",count);
185         Out(count);
186         for(i=0;i<count;i++)      //输出
187         {
188             //printf(" %d",ans[i]);
189             putchar(' ');
190             Out(ans[i]);
191         }
192     //    printf("\n");
193         putchar('\n');
194     }
195 }
196 int main()
197 {
198     int t,cas;;
199 //    scanf("%d",&t);
200     t=Scan();
201     for(cas=1;cas<=t;cas++)
202     {
203         init();
204         build();
205         printf("Case #%d:\n",cas);
206         solve();
207     }
208     return 0;
209 }
View Code

 

posted on 2013-10-25 01:11  jumpingfrog0  阅读(1597)  评论(0编辑  收藏  举报

导航