题意:有N个王子M个公主,王子喜欢一些公主,而且只能是王子喜欢的人,他们才可以结婚,现在让他们尽可能多的结婚的前提下找出来每个王子都可以和谁结婚。
分析:先求出来他们的最大匹配,因为给的数据未必是完备匹配,所以需要添加一些点使他们成为完备匹配才能求出来的环是完整的,比如第二组数据:
1 2
2 1 2
如果不添加虚拟点做成匹配,只会匹配成功一个,这样就找不出来环了,所以需要添加虚拟的王子和公主,虚拟的王子喜欢所有的公主,虚拟的公主被所有的王子喜欢,注意都是王子喜欢公主的,公主没有选择喜欢的权利(确实有点悲哀- -)
*************************************************************************
#include<stdio.h>
#include< string.h>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 2005;
const int Base = 500;
/// base 王子的编号从1开始 公主的编号从base+1开始, 虚拟点的编号从base*2+1开始
int N, M;
bool love[ 1005][ 1005];
vector< vector < int> >ans;
/* **************邻接表******************** */
struct Edge{ int v, next;}e[MAXN*MAXN];
int Head[MAXN], cnt;
void AddEdge( int u, int v)
{
e[cnt].v = v;
e[cnt].next = Head[u];
Head[u] = cnt++;
}
/* *************Tarjan********************* */
int dfn[MAXN], low[MAXN], Index;
int Stack[MAXN], instack[MAXN], top;
int belong[MAXN], bnt;
void Tarjan( int i)
{
int v;
dfn[i] = low[i] = ++Index;
Stack[++top] = i, instack[i] = true;
for( int j=Head[i]; j!=- 1; j=e[j].next)
{
v = e[j].v;
if( !dfn[v] )
{
Tarjan(v);
low[i] = min(low[i], low[v]);
}
else if( instack[v] )
low[i] = min(low[i], dfn[v]);
}
if(low[i] == dfn[i])
{
++bnt;
do
{
v = Stack[top--];
instack[v] = false;
belong[v] = bnt;
if(v > Base)
ans[bnt].push_back(v-Base);
}
while(i != v);
}
}
/* **************匈牙利******************* */
int Lx[MAXN], Ly[MAXN];
bool used[MAXN];
bool Find( int i)
{
for( int j=Head[i]; j!=- 1; j=e[j].next)
{
int v = e[j].v;
if( !used[v] )
{
used[v] = true;
if( !Ly[v] || Find(Ly[v]) )
{
Ly[v] = i;
Lx[i] = v;
return true;
}
}
}
return false;
}
void XYL() /// 顺便添加虚拟点
{
int i, j, k, sum= 0;
for(i= 1; i<=N; i++)
{
memset(used, false, sizeof(used));
sum += Find(i);
}
k = Base * 2 + 1; /// 虚拟点开开始处
for(i= 1; i<=N; i++)
{ /// 遍历王子部分,看那个王子没有匹配,为他虚拟一个公主,这个公主所有的王子都喜欢
if(Lx[i] == false)
{
Lx[i] = k;
Ly[k] = i;
for(j= 1; j<=N; j++)
AddEdge(j, k);
k++;
}
}
for(i=Base+ 1; i<=Base+M; i++)
{ /// 遍历公主部分,看哪个公主没有匹配,为她虚拟一个王子,这个王子喜欢所有的公主
if(Ly[i] == false)
{
Lx[k] = i;
Ly[i] = k;
for(j=Base+ 1; j<=Base+M; j++)
AddEdge(k, j);
k++;
}
}
for(i=Base+ 1; i<k; i++)
{ /// 匹配的点添加反边
AddEdge( i, Ly[i] );
}
}
/* **************初始化******************* */
void InIt()
{
ans.clear();
ans.resize(MAXN);
memset(love, false, sizeof(love));
memset(dfn, false, sizeof(dfn));
memset(Head, - 1, sizeof(Head));
memset(Lx, false, sizeof(Lx));
memset(Ly, false, sizeof(Ly));
cnt = Index = bnt = 0;
}
/* **************************************** */
int main()
{
int T, t= 1;
scanf( " %d ", &T);
while(T--)
{
int i, j, v, Len;
scanf( " %d%d ", &N, &M);
InIt();
for(i= 1; i<=N; i++)
{
scanf( " %d ", &Len);
while(Len--)
{
scanf( " %d ", &v);
AddEdge(i, v+Base);
love[i][v] = true;
}
}
XYL();
for(i= 1; i<=N; i++)
{
if( !dfn[i] )
Tarjan(i);
}
printf( " Case #%d:\n ", t++);
for(i= 1; i<=N; i++)
{
v = belong[i];
Len = ans[v].size();
int a[MAXN], k= 0;
for(j= 0; j<Len; j++)
{ /// 王子必须喜欢这个公主才行
if(love[i][ ans[v][j] ] == true)
a[k++] = ans[v][j];
}
sort(a, a+k);
printf( " %d ", k);
for(j= 0; j<k; j++)
printf( " %d ", a[j]);
printf( " \n ");
}
}
return 0;
#include< string.h>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 2005;
const int Base = 500;
/// base 王子的编号从1开始 公主的编号从base+1开始, 虚拟点的编号从base*2+1开始
int N, M;
bool love[ 1005][ 1005];
vector< vector < int> >ans;
/* **************邻接表******************** */
struct Edge{ int v, next;}e[MAXN*MAXN];
int Head[MAXN], cnt;
void AddEdge( int u, int v)
{
e[cnt].v = v;
e[cnt].next = Head[u];
Head[u] = cnt++;
}
/* *************Tarjan********************* */
int dfn[MAXN], low[MAXN], Index;
int Stack[MAXN], instack[MAXN], top;
int belong[MAXN], bnt;
void Tarjan( int i)
{
int v;
dfn[i] = low[i] = ++Index;
Stack[++top] = i, instack[i] = true;
for( int j=Head[i]; j!=- 1; j=e[j].next)
{
v = e[j].v;
if( !dfn[v] )
{
Tarjan(v);
low[i] = min(low[i], low[v]);
}
else if( instack[v] )
low[i] = min(low[i], dfn[v]);
}
if(low[i] == dfn[i])
{
++bnt;
do
{
v = Stack[top--];
instack[v] = false;
belong[v] = bnt;
if(v > Base)
ans[bnt].push_back(v-Base);
}
while(i != v);
}
}
/* **************匈牙利******************* */
int Lx[MAXN], Ly[MAXN];
bool used[MAXN];
bool Find( int i)
{
for( int j=Head[i]; j!=- 1; j=e[j].next)
{
int v = e[j].v;
if( !used[v] )
{
used[v] = true;
if( !Ly[v] || Find(Ly[v]) )
{
Ly[v] = i;
Lx[i] = v;
return true;
}
}
}
return false;
}
void XYL() /// 顺便添加虚拟点
{
int i, j, k, sum= 0;
for(i= 1; i<=N; i++)
{
memset(used, false, sizeof(used));
sum += Find(i);
}
k = Base * 2 + 1; /// 虚拟点开开始处
for(i= 1; i<=N; i++)
{ /// 遍历王子部分,看那个王子没有匹配,为他虚拟一个公主,这个公主所有的王子都喜欢
if(Lx[i] == false)
{
Lx[i] = k;
Ly[k] = i;
for(j= 1; j<=N; j++)
AddEdge(j, k);
k++;
}
}
for(i=Base+ 1; i<=Base+M; i++)
{ /// 遍历公主部分,看哪个公主没有匹配,为她虚拟一个王子,这个王子喜欢所有的公主
if(Ly[i] == false)
{
Lx[k] = i;
Ly[i] = k;
for(j=Base+ 1; j<=Base+M; j++)
AddEdge(k, j);
k++;
}
}
for(i=Base+ 1; i<k; i++)
{ /// 匹配的点添加反边
AddEdge( i, Ly[i] );
}
}
/* **************初始化******************* */
void InIt()
{
ans.clear();
ans.resize(MAXN);
memset(love, false, sizeof(love));
memset(dfn, false, sizeof(dfn));
memset(Head, - 1, sizeof(Head));
memset(Lx, false, sizeof(Lx));
memset(Ly, false, sizeof(Ly));
cnt = Index = bnt = 0;
}
/* **************************************** */
int main()
{
int T, t= 1;
scanf( " %d ", &T);
while(T--)
{
int i, j, v, Len;
scanf( " %d%d ", &N, &M);
InIt();
for(i= 1; i<=N; i++)
{
scanf( " %d ", &Len);
while(Len--)
{
scanf( " %d ", &v);
AddEdge(i, v+Base);
love[i][v] = true;
}
}
XYL();
for(i= 1; i<=N; i++)
{
if( !dfn[i] )
Tarjan(i);
}
printf( " Case #%d:\n ", t++);
for(i= 1; i<=N; i++)
{
v = belong[i];
Len = ans[v].size();
int a[MAXN], k= 0;
for(j= 0; j<Len; j++)
{ /// 王子必须喜欢这个公主才行
if(love[i][ ans[v][j] ] == true)
a[k++] = ans[v][j];
}
sort(a, a+k);
printf( " %d ", k);
for(j= 0; j<k; j++)
printf( " %d ", a[j]);
printf( " \n ");
}
}
return 0;
}