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 }
posted on 2013-10-25 01:11 jumpingfrog0 阅读(1609) 评论(0) 编辑 收藏 举报