http://acm.hdu.edu.cn/showproblem.php?pid=4685
先找最大匹配数ret
然后把将n这一边的大于n的m-ret与m这一边的n+m-ret边连起来,将n这一边的n+m-ret与m这一边的大于m的n-ret连起来,做最大匹配,得到一个匹配
然后根据这个匹配找强连通分量,属于同一强连通分量的priceness和price可以任意配
同一强连通分量的所有priceness可以给同一强连通分量的price。
用hopcroft-karp算法890ms,用匈牙利算法2656ms。。。
顺便在代码中附上hopcroft-karp算法和找强连通分量的模板~
1 /** 2 *先找最大匹配ret 3 *然后把将n和m以上的n+m-ret边连起来做最大匹配 4 *然后按这个匹配找强连通分量,属于同一强连通分量的priceness和price可以任意配 5 * 6 *@Author: xiaohai---xysmlx 7 */ 8 //#pragma comment(linker, "/STACK:102400000,102400000") 9 #include<cstdio> 10 #include<iostream> 11 #include<cstring> 12 #include<string> 13 #include<cmath> 14 #include<set> 15 #include<list> 16 #include<map> 17 #include<iterator> 18 #include<cstdlib> 19 #include<vector> 20 #include<queue> 21 #include<stack> 22 #include<algorithm> 23 #include<functional> 24 using namespace std; 25 typedef long long LL; 26 #define ROUND(x) round(x) 27 #define FLOOR(x) floor(x) 28 #define CEIL(x) ceil(x) 29 const int maxn=1010; 30 const int maxm=maxn*maxn; 31 const int inf=0x3f3f3f3f; 32 const LL inf64=0x3f3f3f3f3f3f3f3fLL; 33 const double INF=1e30; 34 const double eps=1e-6; 35 36 /** 37 *大数据二分图匹配:Hopcroft-Karp($O(sqrt{V}E)$) 38 *适用于数据较大的二分匹配(从0到n-1) 39 *输入:Nx,Ny,g[][] 40 *输出:res=MaxMatch(); 41 */ 42 int g[maxn][maxn],Mx[maxn],My[maxn],Nx,Ny; 43 int dx[maxn],dy[maxn],dis; 44 bool vst[maxn]; 45 int res; 46 bool searchP() 47 { 48 queue<int>Q; 49 dis=inf; 50 memset(dx,-1,sizeof(dx)); 51 memset(dy,-1,sizeof(dy)); 52 for(int i=0; i<Nx; i++) 53 if(Mx[i]==-1) 54 { 55 Q.push(i); 56 dx[i]=0; 57 } 58 while(!Q.empty()) 59 { 60 int u=Q.front(); 61 Q.pop(); 62 if(dx[u]>dis) break; 63 for(int v=0; v<Ny; v++) 64 if(g[u][v]&&dy[v]==-1) 65 { 66 dy[v]=dx[u]+1; 67 if(My[v]==-1) dis=dy[v]; 68 else 69 { 70 dx[My[v]]=dy[v]+1; 71 Q.push(My[v]); 72 } 73 } 74 } 75 return dis!=inf; 76 } 77 bool DFS(int u) 78 { 79 for(int v=0; v<Ny; v++) 80 if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1) 81 { 82 vst[v]=1; 83 if(My[v]!=-1&&dy[v]==dis) continue; 84 if(My[v]==-1||DFS(My[v])) 85 { 86 My[v]=u; 87 Mx[u]=v; 88 return 1; 89 } 90 } 91 return 0; 92 } 93 int MaxMatch() 94 { 95 int res=0; 96 memset(Mx,-1,sizeof(Mx)); 97 memset(My,-1,sizeof(My)); 98 while(searchP()) 99 { 100 memset(vst,0,sizeof(vst)); 101 for(int i=0; i<Nx; i++) 102 if(Mx[i]==-1&&DFS(i)) res++; 103 } 104 return res; 105 } 106 107 /** 108 *有向图强连通分量:Tarjan算法($O(V+E)$) 109 *输入:图(从0到n-1) 110 *输出:sid[](强连通分量标号) 111 */ 112 //const int maxn=0; 113 //const int maxm=0; 114 struct Edge 115 { 116 int v,w; 117 int next; 118 } edge[maxm]; 119 int head[maxn],edgeNum; 120 void addSubEdge(int u,int v) 121 { 122 edge[edgeNum].v=v; 123 edge[edgeNum].next=head[u]; 124 head[u]=edgeNum++; 125 } 126 void addEdge(int u,int v) 127 { 128 addSubEdge(u,v); 129 addSubEdge(v,u); 130 } 131 int sid[maxn]; 132 int mark[maxn],low[maxn]; 133 int check[maxn]; 134 int sstack[maxn],top; 135 int dfn,ssn; 136 int n,m; 137 void dfs(int k) 138 { 139 int i,j; 140 check[k]=1; 141 low[k]=mark[k]=dfn++; 142 sstack[top++]=k; 143 for(int i=head[k]; i!=-1; i=edge[i].next) 144 { 145 int j=edge[i].v; 146 if(mark[j]==0) 147 { 148 dfs(j); 149 low[k]=min(low[k],low[j]); 150 } 151 else if(check[j]) 152 low[k]=min(low[k],mark[j]); 153 } 154 if(mark[k]==low[k]) 155 { 156 while(sstack[--top]!=k) 157 { 158 check[sstack[top]]=0; 159 sid[sstack[top]]=ssn; 160 } 161 sid[k]=ssn; 162 check[k]=0; 163 ++ssn; 164 } 165 return; 166 } 167 void tarjan() 168 { 169 ssn=1; 170 dfn=1; 171 top=0; 172 memset(check,0,sizeof(check)); 173 memset(mark,0,sizeof(mark)); 174 for(int i=0; i<n; ++i) if(mark[i]==0) dfs(i); 175 } 176 177 int N,M; 178 void init() 179 { 180 memset(g,0,sizeof(g)); 181 memset(head,-1,sizeof(head)); 182 edgeNum=0; 183 } 184 void input() 185 { 186 scanf("%d%d",&N,&M); 187 Nx=N; 188 Ny=M; 189 for(int i=0; i<Nx; i++) 190 { 191 int k; 192 scanf("%d",&k); 193 while(k--) 194 { 195 int x; 196 scanf("%d",&x); 197 g[i][x-1]=1; 198 } 199 } 200 } 201 void solve() 202 { 203 res=MaxMatch(); 204 // cout<<res<<endl; 205 Nx=Ny=N+M-res; 206 for(int i=N; i<Nx; i++) 207 { 208 for(int j=0; j<Ny; j++) 209 { 210 g[i][j]=1; 211 } 212 } 213 for(int i=0; i<Nx; i++) 214 { 215 for(int j=M; j<Ny; j++) 216 { 217 g[i][j]=1; 218 } 219 } 220 res=MaxMatch(); 221 // cout<<res<<endl; 222 // for(int i=0; i<Nx; i++) cout<<Mx[i]<<" "; 223 // cout<<endl; 224 225 for(int i=0; i<Nx; i++) 226 { 227 for(int j=0; j<Ny; j++) 228 { 229 if(g[i][j]&&j!=Mx[i]) 230 { 231 addSubEdge(Mx[i],j); 232 } 233 } 234 } 235 n=Ny; 236 tarjan(); 237 // for(int i=0;i<n;i++) cout<<sid[i]<<" "; 238 // cout<<endl; 239 } 240 int main() 241 { 242 // freopen("in.cpp","r",stdin); 243 int T; 244 scanf("%d",&T); 245 for(int kase=1; kase<=T; kase++) 246 { 247 init(); 248 input(); 249 solve(); 250 251 printf("Case #%d: ",kase); 252 vector<int> ans; 253 for(int i=0; i<N; i++) 254 { 255 ans.clear(); 256 for(int j=0; j<M; j++) 257 { 258 if(g[i][j]&&sid[Mx[i]]==sid[j]) 259 { 260 ans.push_back(j+1); 261 } 262 } 263 printf("%d",ans.size()); 264 for(int i=0; i<ans.size(); i++) 265 { 266 printf(" %d",ans[i]); 267 } 268 puts(""); 269 } 270 } 271 return 0; 272 }