HDU 4685 Prince and Princess (2013多校8 1010题 二分匹配+强连通)

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 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/kuangbin/p/3261157.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞