传送门:Problem 1904

https://www.cnblogs.com/violet-acmer/p/9739990.html

参考资料:

  [1]:http://www.cnblogs.com/frog112111/p/3384261.html

  [2]:https://blog.csdn.net/a709743744/article/details/52133778

  [3]:http://www.cppblog.com/Uriel/articles/121169.html

题意:

  有n个王子,每个王子都有k个喜欢的妹子,每个王子只能和喜欢的妹子结婚,大臣给出一个匹配表,每个王子都和一个妹子结婚,但是国王不满意,他要求大臣给他另一个表,每个王子可以和几个妹子结婚,按序号升序输出妹子的编号,这个表应满足所有的王子最终都有妹子和他结婚。

分析:

  很好的图论题,把强连通分量和完美匹配结合起来了。

  2*N 个顶点的2 分图,并且给了一个完美匹配(Perfect Matching)以及每个顶点可以连接的其他的顶点。

  题目要求是否可以确定某 2 个顶点连边后,其他 2*(N - 1) 个顶点的 2 分图是否可以构成完美匹配。

建图:

  如果王子u喜欢妹子v,则建一条边u指向v(u,v),对于大臣给出的初始完美匹配,如果王子u和妹子v结婚,则建一条边v指向u(v,u),然后求强连通分量。

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

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

所以一个王子可以和所有与他同一强连通分量的妹子结婚,而这不会导致同一强连通分量中的其他王子找不到妹子结婚。

  (证明:王子为什么不能选择不同强连通分量的妹子:

  反证法:如果强连通分量 1 中的王子选择了强连通分量 2 中的妹子,那么势必强连通分量 2 中的一个王子无法在自己的强连通分量中找到妹子,那么他就会去别的强连通分量找妹子,这样一直循环下去,我们知道最终一定是经过了强连通分量 1,2,x1,x2,xn,……,1,王子们才能都找到自己的妹子,这样这些强连通分量1,2,x1,x2,xn,……,1会构成一个强连通分量,与题设在不同强连通分量中找妹子不符)

此题难点:建图

AC代码:

这一题的数据量挺大的,光是输入输出就会消耗很多时间了,可以用输入输出外挂来加速读入和输出。

Kosaraju算法:

 #include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define mem(a,b) memset(a,b,sizeof a)
#define pb push_back
const int maxV=4e3+; int scc[maxV];
bool vis[maxV];
vector<int >vs;
vector<int >edge[maxV],redge[maxV]; void addEdge(int u,int v)
{
edge[u].pb(v);
redge[v].pb(u);
}
void Dfs(int u)
{
vis[u]=true;
for(int i=;i < edge[u].size();++i)
{
int to=edge[u][i];
if(!vis[to])
Dfs(to);
}
vs.pb(u);
}
void rDfs(int u,int sccId)
{
scc[u]=sccId;
vis[u]=true;
for(int i=;i < redge[u].size();++i)
{
int to=redge[u][i];
if(!vis[to])
rDfs(to,sccId);
}
}
void Scc(int maxV)
{
mem(vis,false);
vs.clear();
for(int i=;i <= maxV;++i)
if(!vis[i])
Dfs(i);
mem(vis,false);
int sccId=;
for(int i=vs.size()-;i >= ;--i)
{
int v=vs[i];
if(!vis[v])
{
sccId++;
rDfs(v,sccId);
}
}
}
int main()
{
int N;
scanf("%d",&N);
for(int i=;i <= N;++i)
{
int k,v;
scanf("%d",&k);
while(k--)
{
scanf("%d",&v);
addEdge(i,v+N);//王子i喜欢妹子v
}
}
for(int i=;i <= N;++i)
{
int v;
scanf("%d",&v);
addEdge(v+N,i);//王子i可以和妹子v结婚
}
Scc(N);
for(int i=;i <= N;++i)
{
int res=;
int ans[maxV];
for(int j=;j < edge[i].size();++j)
{
int to=edge[i][j];
if(scc[i] == scc[to])//同一个强连通分量
ans[res++]=to;
}
sort(ans,ans+res);
printf("%d",res);
for(int j=;j < res;++j)
printf(" %d",ans[j]-N);
printf("\n");
}
}

不用输入输出挂

 #include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define mem(a,b) memset(a,b,sizeof a)
#define pb push_back
const int maxV=4e3+; int scc[maxV];
bool vis[maxV];
vector<int >vs;
vector<int >edge[maxV],redge[maxV]; void addEdge(int u,int v)
{
edge[u].pb(v);
redge[v].pb(u);
}
void Dfs(int u)
{
vis[u]=true;
for(int i=;i < edge[u].size();++i)
{
int to=edge[u][i];
if(!vis[to])
Dfs(to);
}
vs.pb(u);
}
void rDfs(int u,int sccId)
{
scc[u]=sccId;
vis[u]=true;
for(int i=;i < redge[u].size();++i)
{
int to=redge[u][i];
if(!vis[to])
rDfs(to,sccId);
}
}
void Scc(int maxV)
{
mem(vis,false);
vs.clear();
for(int i=;i <= maxV;++i)
if(!vis[i])
Dfs(i);
mem(vis,false);
int sccId=;
for(int i=vs.size()-;i >= ;--i)
{
int v=vs[i];
if(!vis[v])
{
sccId++;
rDfs(v,sccId);
}
}
}
//===============输入输出挂===============
int Scan() //输入外挂
{
int res=,ch,flag=;
if((ch=getchar())=='-')
flag=;
else if(ch>=''&&ch<='')
res=ch-'';
while((ch=getchar())>=''&&ch<='')
res=res*+ch-''; return flag?-res:res;
}
void Out(int a) //输出外挂
{
if(a>)
Out(a/);
putchar(a%+'');
}
//========================================
int main()
{
int N;
scanf("%d",&N);
for(int i=;i <= N;++i)
{
int k,v;
//scanf("%d",&k);
k=Scan();
while(k--)
{
//scanf("%d",&v);
v=Scan();
addEdge(i,v+N);//王子i喜欢妹子v
}
}
for(int i=;i <= N;++i)
{
int v;
//scanf("%d",&v);
v=Scan();
addEdge(v+N,i);//王子i可以和妹子v结婚
}
Scc(N);
for(int i=;i <= N;++i)
{
int res=;
int ans[maxV];
for(int j=;j < edge[i].size();++j)
{
int to=edge[i][j];
if(scc[i] == scc[to])//同一个强连通分量
ans[res++]=to;
}
sort(ans,ans+res);
//printf("%d",res);
Out(res);
for(int j=;j < res;++j)
{
printf(" ");
Out(ans[j]-N);
//printf(" %d",ans[j]-N);
}
printf("\n");
}
}

调用输入输出挂

好晚了,身心疲惫,明天在补Tarjan算法...............

poj 1904(强连通分量+完美匹配)的更多相关文章

  1. POJ 1904 King's Quest (强连通分量+完美匹配)

    <题目链接> 题目大意: 有n个王子,每个王子都有k个喜欢的妹子,每个王子只能和喜欢的妹子结婚,大臣给出一个匹配表,每个王子都和一个妹子结婚,但是国王不满意,他要求大臣给他另一个表,每个王 ...

  2. poj 1904(强连通分量+输入输出外挂)

    题目链接:http://poj.org/problem?id=1904 题意:有n个王子,每个王子都有k个喜欢的妹子,每个王子只能和喜欢的妹子结婚,大臣给出一个匹配表,每个王子都和一个妹子结婚,但是国 ...

  3. poj 1904 强连通分量

    思路:先有每个儿子向所有他喜欢的姑娘建边,对于最后给出的正确匹配,我们建由姑娘到相应王子的边.和某个王子在同一强连通分量,且王子喜欢的姑娘都是该王子能娶得.思想类似匈牙利算法求匹配的时候,总能找到增广 ...

  4. poj 2186 强连通分量

    poj 2186 强连通分量 传送门 Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 33414 Acc ...

  5. poj 2762(强连通分量+拓扑排序)

    题目链接:http://poj.org/problem?id=2762 题意:给出一个有向图,判断任意的两个顶点(u,v)能否从u到达v,或v到达u,即单连通,输出Yes或No. 分析:对于同一个强连 ...

  6. poj 1236(强连通分量分解模板题)

    传送门 题意: N(2<N<100)个学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输. 问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都 ...

  7. POJ(2186)强连通分量分解

    #include<cstdio> #include<vector> #include<cstring> using namespace std; ; vector& ...

  8. Popular Cows POJ - 2186(强连通分量)

    Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10, ...

  9. POJ 1904 King's Quest ★(强连通分量:可行完美匹配边)

    题意 有n个女生和n个男生,给定一些关系表示男生喜欢女生(即两个人可以结婚),再给定一个初始匹配,表示这个男生和哪个女生结婚,初始匹配必定是合法的.求每个男生可以和哪几个女生可以结婚且能与所有人不发生 ...

随机推荐

  1. sublime text3 安装package control 出现问题解决过程记录

    1.安装package control 失败 通过最简单的自动安装 package control 失败(详见package control官网). 报错展示: File "./python ...

  2. A. Make a triangle!

    题意 给你三条边a,b,c问使得构成三角形,需要增加的最少长度是多少 思路 数学了啦 代码 #include<bits/stdc++.h> using namespace std; #de ...

  3. C. Sequence Transformation

    链接 [http://codeforces.com/contest/1059/problem/C] 题意 给你一个n,有个序列有n个元素分别时1 ~ n,每次去掉一个元素输出剩下元素的GCD,使得最后 ...

  4. 作业20171102 beta1 成绩

    申诉 对成绩有疑问或不同意见的同学,请在群里[@杨贵福]. 申诉时间截止2017年12月12日 17:00. 成绩 scrum01 scrum02 scrum03 scrum04 scrum05 sc ...

  5. 【个人阅读】软件工程M1/M2阶段总结

    这次作业是好久以前布置的,由于学期末课程设计任务比较重,我在完善M2阶段的代码的同时又忙于数据库的实现和编译器的实现,一度感觉忙得透不过气来....到这些都基本完成的时候,会看自己以前的阅读心得,觉得 ...

  6. Linux实践一:问题及解决

    安装ubuntu出现的问题 : 打开镜像.iso文件,v-box好像是不识别这种格式的,它识别的好像是.vdi等格式,所以要用vm虚拟机打开镜像安装 打开镜像,按照步骤安装后,安装很久后,出现问题.初 ...

  7. Redis持久化的两种方式和区别

    该文转载自:http://www.cnblogs.com/swyi/p/6093763.html Redis持久化的两种方式和区别 Redis是一种高级key-value数据库.它跟memcached ...

  8. Eclipse频繁崩溃问题待解决

    ---------------------------Eclipse---------------------------Java was started but returned exit code ...

  9. windows 与linux 上面PG的简单验证

    0.0 目的 验证一下 windows 上面 和linux上面的数据文件是否可以 冷备份 恢复. 1 方法关闭 windows机器上面postgresql 的服务 我这边是PG10.4 可以使用命令 ...

  10. Jenkins 登录提示 登录无效 的解决办法

    学习自:https://www.cnblogs.com/amberly/p/6288773.html 1. jenkins服务器重启之后, 再次登录提示登录无效. 重启多次也无法解决. 2. 根据文档 ...