Prince and Princess
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 150 Accepted Submission(s): 46
Problem Description There are n princes and m princesses. Princess can marry any prince. But prince can only marry the princess they DO love.
For all princes,give all the princesses that they love. So, there is a maximum number of pairs of prince and princess that can marry.
Now for each prince, your task is to output all the princesses he can marry. Of course if a prince wants to marry one of those princesses,the maximum number of marriage pairs of the rest princes and princesses cannot change.
Input The first line of the input contains an integer T(T<=25) which means the number of test cases.
For each test case, the first line contains two integers n and m (1<=n,m<=500), means the number of prince and princess.
Then n lines for each prince contain the list of the princess he loves. Each line starts with a integer k
i(0<=k
i<=m), and then k
i different integers, ranging from 1 to m denoting the princesses.
Output For each test case, first output “Case #x:” in a line, where x indicates the case number between 1 and T.
Then output n lines. For each prince, first print li, the number of different princess he can marry so that the rest princes and princesses can still get the maximum marriage number.
After that print li different integers denoting those princesses,in ascending order.
Sample Input 2 4 4 2 1 2 2 1 2 2 2 3 2 3 4 1 2 2 1 2
Sample Output Case #1: 2 1 2 2 1 2 1 3 1 4 Case #2: 2 1 2
Source
2013 Multi-University Training Contest 8
Recommend zhuyuanchen520
主要构图转化的思路很神奇,我看了题解才会的,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 }