Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 150 Accepted Submission(s): 46
主要构图转化的思路很神奇,我看了题解才会的,T_T
首先n,m个点做一次二分匹配,得到匹配数最大为res. 相当于右边有m-res个点没有匹配,左边有n-res个点没有匹配。
所以在左加m-res个点,和右边所有相连。
在右边加n-res个点,个左边所有相连。
然后做n+m-res,n+m-res个点的二分匹配。
匹配数肯定是n+m-res;
主要是得到匹配的情况。
对于左边的点i. 把i相匹配的在右边的点,向其余和i相连的点连一有向边。
然后做强连通缩点。
如果边u-v. v和u匹配的点在一个连通分支,说明可以交换,可以u->v组合,不影响最大匹配数
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013/8/15 23:20:43 4 File Name :F:\2013ACM练习\2013多校8\1010.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const int MAXN = 1010; 21 int uN,vN; 22 int g[MAXN][MAXN]; 23 int linker[MAXN]; 24 bool used[MAXN]; 25 bool dfs(int u) 26 { 27 for(int v = 1; v <= vN;v++) 28 if(g[u][v] && !used[v]) 29 { 30 used[v] = true; 31 if(linker[v] == -1 || dfs(linker[v])) 32 { 33 linker[v] = u; 34 return true; 35 } 36 } 37 return false; 38 } 39 int hungary() 40 { 41 int res = 0; 42 memset(linker,-1,sizeof(linker)); 43 for(int u = 1; u <= uN;u++) 44 { 45 memset(used,false,sizeof(used)); 46 if(dfs(u))res++; 47 } 48 return res; 49 } 50 int lx[MAXN]; 51 const int MAXM = 500100;//边数 52 struct Edge 53 { 54 int to,next; 55 }edge[MAXM]; 56 int head[MAXN],tot; 57 int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc 58 int Index,top; 59 int scc;//强连通分量的个数 60 bool Instack[MAXN]; 61 int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc 62 //num数组不一定需要,结合实际情况 63 64 void addedge(int u,int v) 65 { 66 edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++; 67 } 68 void Tarjan(int u) 69 { 70 int v; 71 Low[u] = DFN[u] = ++Index; 72 Stack[top++] = u; 73 Instack[u] = true; 74 for(int i = head[u];i != -1;i = edge[i].next) 75 { 76 v = edge[i].to; 77 if( !DFN[v] ) 78 { 79 Tarjan(v); 80 if( Low[u] > Low[v] )Low[u] = Low[v]; 81 } 82 else if(Instack[v] && Low[u] > DFN[v]) 83 Low[u] = DFN[v]; 84 } 85 if(Low[u] == DFN[u]) 86 { 87 scc++; 88 do 89 { 90 v = Stack[--top]; 91 Instack[v] = false; 92 Belong[v] = scc; 93 num[scc]++; 94 } 95 while( v != u); 96 } 97 } 98 void solve(int N) 99 { 100 memset(DFN,0,sizeof(DFN)); 101 memset(Instack,false,sizeof(Instack)); 102 memset(num,0,sizeof(num)); 103 Index = scc = top = 0; 104 for(int i = 1;i <= N;i++) 105 if(!DFN[i]) 106 Tarjan(i); 107 } 108 void init() 109 { 110 tot = 0; 111 memset(head,-1,sizeof(head)); 112 } 113 114 int main() 115 { 116 //freopen("in.txt","r",stdin); 117 //freopen("out.txt","w",stdout); 118 int n,m; 119 int k; 120 int T; 121 scanf("%d",&T); 122 int iCase = 0; 123 while(T--) 124 { 125 iCase++; 126 scanf("%d%d",&n,&m); 127 memset(g,0,sizeof(g)); 128 int v; 129 for(int i = 1;i <= n;i++) 130 { 131 scanf("%d",&k); 132 while(k--) 133 { 134 scanf("%d",&v); 135 g[i][v] = 1; 136 } 137 } 138 uN = n; 139 vN = m; 140 int res = hungary(); 141 uN = vN = n + m - res; 142 for(int i = n+1;i <= uN;i++) 143 for(int j = 1;j <= vN;j++) 144 g[i][j] = 1; 145 for(int i = 1;i <= uN;i++) 146 for(int j = m+1;j <= vN;j++) 147 g[i][j] = 1; 148 hungary(); 149 memset(lx,-1,sizeof(lx)); 150 for(int i = 1;i <= vN;i++) 151 if(linker[i] != -1) 152 lx[linker[i]] = i; 153 init(); 154 for(int i = 1;i <= uN;i++) 155 for(int j = 1;j <= vN;j++) 156 if(g[i][j] && j != lx[i]) 157 addedge(lx[i],j); 158 solve(vN); 159 printf("Case #%d:\n",iCase); 160 vector<int>ans; 161 for(int i = 1;i <= n;i++) 162 { 163 ans.clear(); 164 for(int j = 1; j <= m;j++) 165 if(g[i][j] && Belong[j] == Belong[lx[i]]) 166 ans.push_back(j); 167 int sz = ans.size(); 168 printf("%d",sz); 169 for(int i = 0;i < sz;i++) 170 printf(" %d",ans[i]); 171 printf("\n"); 172 } 173 } 174 return 0; 175 }