您的位置:首页 > 产品设计 > UI/UE

POJ 1904 King's Quest && HDU 4685 Prince and Princess (强联通解决二分图可行匹配问题)

2017-09-22 11:41 507 查看
King's Quest

Time Limit: 15000MS Memory Limit: 65536K
Total Submissions: 9427 Accepted: 3483
Case Time Limit: 2000MS
Description

Once upon a time there lived a king and he had N sons. And there were N beautiful girls in the kingdom and the king knew about each of his sons which of those girls he did like. The sons of the king were young and light-headed, so it was possible for one son
to like several girls. 

So the king asked his wizard to find for each of his sons the girl he liked, so that he could marry her. And the king's wizard did it -- for each son the girl that he could marry was chosen, so that he liked this girl and, of course, each beautiful girl had
to marry only one of the king's sons. 

However, the king looked at the list and said: "I like the list you have made, but I am not completely satisfied. For each son I would like to know all the girls that he can marry. Of course, after he marries any of those girls, for each other son you must
still be able to choose the girl he likes to marry." 

The problem the king wanted the wizard to solve had become too hard for him. You must save wizard's head by solving this problem. 

Input

The first line of the input contains N -- the number of king's sons (1 <= N <= 2000). Next N lines for each of king's sons contain the list of the girls he likes: first Ki -- the number of those girls, and then Ki different integer numbers, ranging from 1 to
N denoting the girls. The sum of all Ki does not exceed 200000. 

The last line of the case contains the original list the wizard had made -- N different integer numbers: for each son the number of the girl he would marry in compliance with this list. It is guaranteed that the list is correct, that is, each son likes the
girl he must marry according to this list. 

Output

Output N lines.For each king's son first print Li -- the number of different girls he likes and can marry so that after his marriage it is possible to marry each of the other king's sons. After that print Li different integer numbers denoting those girls, in
ascending order.
Sample Input
4
2 1 2
2 1 2
2 2 3
2 3 4
1 2 3 4

Sample Output
2 1 2
2 1 2
1 3
1 4

Hint

This problem has huge input and output data,use scanf() and printf() instead of cin and cout to read data to avoid time limit exceed.
Source

Northeastern Europe 2003

题目大意:一个国王有n个王子,同时有n个女孩。每个王子都有自己喜欢的若干个女孩,现给定一个合法的完备匹配(也就是一个王子娶其中一个自己喜欢女孩),求每个王子可以选择哪些女孩可以让剩下的每个王子依旧能够选择到自己喜欢的一个女孩。

思路:

1

其实就是求王子能和哪些女孩结婚,不影响最大匹配;

 假如已知匹配王子属于x,女孩属于y

现有匹配xi---yi xj---yj 并且xi也喜欢yj

如果说xi能和yj匹配并不改变匹配总数,必须满足一下两个条件之一:

1:xj也喜欢yi;

2:yi 被某个匹配中的 xk喜欢,并且 xi 也喜欢 yk ;

思路很像匈牙利算法中找曾广路的过程;xi--->yj--->xk--->yi--->xi(是一个环,各点都能相互到达,所以其中的匹配可以互换,并且不影响匹配总数);

 

建图:王子u喜欢女孩v,则u到v连一条边。对于给出的初始完美匹配,王子u与女孩v匹配,则v到u连一条边。然后求SCC。

显然对于同一个SCC中王子数目和女孩数目是相等的,并且从某个王子出发能够到达所有女孩,这样,王子可以和属于同一个SCC中的任意一个女孩结婚,而不会影响其他王子。

对于每个王子和妹子,如果他们都在同一个强连通分量内,则他们可以结婚。

为什么呢?因为每个王子只能和喜欢的妹子结婚,初始完美匹配中的丈夫和妻子之间有两条方向不同的边可以互达,则同一个强连通分量中的王子数和妹子数一定是相等的,若王子x可以和另外的一个妹子a结婚,妹子a的原配王子y肯定能找到另外一个妹子b结婚,因为如果找不到的话,则x和a必不在同一个强连通分量中。

所以一个王子可以和所有与他同一强连通分量的妹子结婚,而这不会导致同一强连通分量中的其他王子找不到妹子结婚。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 4e3 + 5;
int n, m, low[maxn], dfn[maxn], id[maxn], scc_cnt, dfs_cnt, ans[maxn];
int in[maxn], out[maxn];
vector<int> v[maxn];
stack<int> s;
void init()
{
memset(low, 0, sizeof(low));
memset(id, 0, sizeof(id));
memset(dfn, 0, sizeof(dfn));
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(ans, 0, sizeof(ans));
scc_cnt = dfs_cnt = 0;
for(int i = 0; i < maxn; i++)
v[i].clear();
while(!s.empty())
s.pop();
}
void tarjan(int x)
{
dfn[x] = low[x] = ++dfs_cnt;
s.push(x);
for(int i = 0; i < v[x].size(); i++)
{
int to = v[x][i];
if(!dfn[to])
{
tarjan(to);
low[x] = min(low[x], low[to]);
}
else if(!id[to])
low[x] = min(low[x], dfn[to]);
}
if(low[x] == dfn[x])
{
scc_cnt++;
while(1)
{
int u = s.top();
s.pop();
id[u] = scc_cnt;
if(x == u) break;
}
}
}
void scc()
{
for(int i = 1; i <= 2*n ; i++) //这里要*2
if(!dfn[i])
tarjan(i);
}
int main()
{
int _, ca = 1;
while(~scanf("%d", &n))
{
init();
for(int i = 1; i <= n; i++)
{
int k, x, y;
scanf("%d", &k);
while(k--)
{
scanf("%d", &x);
v[i].push_back(n+x);
}
}
for(int i = 1; i <= n; i++)
{
int x;
scanf("%d", &x);
v[x+n].push_back(i);
}
scc();
for(int i = 1; i <= n; i++)
{
int k = 0;
for(int j = 0; j < v[i].size(); j++)
{
int to = v[i][j];
if(id[i] == id[to])
{
ans[k++] = to-n;
}
}
sort(ans, ans+k);
printf("%d", k);
for(int i = 0; i < k; i++)
printf(" %d", ans[i]);
puts("");
}
}
return 0;
}


Prince and Princess

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)

Total Submission(s): 1903    Accepted Submission(s): 569


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 ki(0<=ki<=m), and then ki 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 4Case #2:
2 1 2

 

Source

2013 Multi-University Training Contest 8

 

Recommend

zhuyuanchen520

 

Statistic | Submit | Discuss | Note

大意就是

有n个王子和m个公主

每个王子都会喜欢若干个公主,也就是王子只跟自己喜欢的公主结婚

公主就比较悲惨, 跟谁结婚都行

然后输出王子可能的结婚对象

必须保证王子与任意这些对象中的一个结婚,都不会影响到剩余的王子的配对数,也就是不能让剩余的王子中突然有一个人没婚可结了

然后思路其实跟POJ1904非常像。

但是POJ那题给出了初始的一个完备匹配。

而本题没有

怎么办呢

我们就要想方设法构造出完备匹配

刚开始的时候我们可以先做一遍二分图最大匹配

那么因为两边人数不一等相等,所以可能有人会单身

那么这时候我们就要给这些单身的人安排对象了。

安排的对象不能是已有的这些人中的任何一个,那就只好再虚拟一些人出来了。

这些人比较杯具啊,对象都是虚拟的。

假设王子有剩下的,那么每个剩下的王子就连一个虚拟的公主,这个公主被所有的王子都喜欢。

假设公主有剩下的,那么每个剩下的公主就连一个虚拟的王子,这个王子喜欢所有的公主

做法是先求一次最大匹配设为cnt,那么左边有n-cnt个王子还未匹配,右边有m-cnt个公主还未匹配,因此我们将左侧增加m-cnt个虚拟王子,虚拟王子与右边所有公主连边;右边增加n-cnt个虚拟公主,虚拟公主与左边所有王子连边,这样我们就得到一个两边各有M=n+m-cnt的二分图,且该二分图是一个完美匹配。也就是每个王子都有一个匹配的公主。现在,我们将每个王子匹配的公主向该王子喜欢的公主连边(建一个新图g),然后求g的强连通分量。那么与每个王子之前匹配的公主在一个强连通分量里的公主都可以作为该王子的匹配使得最大匹配不变。为什么是这样的呢?设王子i之前的匹配为p[i],现在为王子i选择一个新的公主j,那么我们若能为p[i]重新找到一个王子k,那么实质上就是找到另一个王子互换两个两个王子喜欢的公主。因此两公主若在一个强连通分量里,那么王子由之前的匹配公主A选择公主B时,A也能找到另一个匹配,因为B能够通过某些路径到达A,等价于这条环上所有王子的匹配都后移一个人而已。

上一题 每个公主只能嫁给一个,这个可以嫁给多个 - -

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int MAXN = 1010;
int uN,vN;
int g[MAXN][MAXN];
int linker[MAXN];
bool used[MAXN];
bool dfs(int u)
{
for(int v = 1; v <= vN;v++)
if(g[u][v] && !used[v])
{
used[v] = true;
if(linker[v] == -1 || dfs(linker[v]))
{
linker[v] = u;
return true;
}
}
return false;
}
int hungary()
{
int res = 0;
memset(linker,-1,sizeof(linker));
for(int u = 1; u <= uN;u++)
{
memset(used,false,sizeof(used));
if(dfs(u))res++;
}
return res;
}
int lx[MAXN];
const int MAXM = 500100;//边数
struct Edge
{
int to,next;
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc
int Index,top;
int scc;//强连通分量的个数
bool Instack[MAXN];
int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc
//num数组不一定需要,结合实际情况

void addedge(int u,int v)
{
edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;
}
void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for(int i = head[u];i != -1;i = edge[i].next)
{
v = edge[i].to;
if( !DFN[v] )
{
Tarjan(v);
if( Low[u] > Low[v] )Low[u] = Low[v];
}
else if(Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if(Low[u] == DFN[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}
while( v != u);
}
}
void solve(int N)
{
memset(DFN,0,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
memset(num,0,sizeof(num));
Index = scc = top = 0;
for(int i = 1;i <= N;i++)
if(!DFN[i])
Tarjan(i);
}
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}

int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m;
int k;
int T;
scanf("%d",&T);
int iCase = 0;
while(T--)
{
iCase++;
scanf("%d%d",&n,&m);
memset(g,0,sizeof(g));
int v;
for(int i = 1;i <= n;i++)
{
scanf("%d",&k);
while(k--)
{
scanf("%d",&v);
g[i][v] = 1;
}
}
uN = n;
vN = m;
int res = hungary();
uN = vN = n + m - res;
for(int i = n+1;i <= uN;i++)
for(int j = 1;j <= vN;j++)
g[i][j] = 1;
for(int i = 1;i <= uN;i++)
for(int j = m+1;j <= vN;j++)
g[i][j] = 1;
hungary();
memset(lx,-1,sizeof(lx));
for(int i = 1;i <= vN;i++)
if(linker[i] != -1)
lx[linker[i]] = i;
init();
for(int i = 1;i <= uN;i++)
for(int j = 1;j <= vN;j++)
if(g[i][j] && j != lx[i])
addedge(lx[i],j);
solve(vN);
printf("Case #%d:\n",iCase);
vector<int>ans;
for(int i = 1;i <= n;i++)
{
ans.clear();
for(int j = 1; j <= m;j++)
if(g[i][j] && Belong[j] == Belong[lx[i]])
ans.push_back(j);
int sz = ans.size();
printf("%d",sz);
for(int i = 0;i < sz;i++)
printf(" %d",ans[i]);
printf("\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: