Time Limit: 15000MS | Memory Limit: 65536K | |
Total Submissions: 4537 | Accepted: 1533 | |
Case Time Limit: 2000MS |
Description
Input
Output
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
题目大意:一个国王有n个王子,同时有n个女孩。每个王子都有自己喜欢的若干个女孩,现给定一个合法的完备匹配(也就是一个王子娶其中一个自己喜欢女孩),求每个王子可以选择哪些女孩可以让剩下的每个王子依旧能够选择到自己喜欢的一个女孩。
解题思路:参考:http://www.cnblogs.com/zxndgv/archive/2011/08/06/2129333.html
这篇文章写得挺好,一开始我也是用了N次找增广路,直接把增广路算出来的方法,无庸置疑的TLE。然后实在无法,参考了这个博客。
他讲的,我就不说了。说说令我思考的问题:为什么图是这么建的。
这个用强连通的方法建图:男的和所有可以他喜欢的女的连一条有向边;女的,则是根据最后的那个匹配来连一条有向边到她所对应的男的。问:为什么这么建?为什么要用有向边?
为什么这么建!当xi的本来就匹配yi的时候,xi有边到yi,yi也有边到xi,直接就是强连通,这是肯定的。然后,我们需要找增广路的时候,必须是从x出发到y,然后到y的匹配的x,一个y只能有一条边到x,造成了不对称性,也就是,可以有好几个x连到同一个y,但每个y连的都有且只有一个x,这种不对称就是有向图。因为利用匈牙利算法的增广路一定是一条不匹配边一条匹配边这样的交替,所以,这样建图是合理的也是必要的。于是,也就不用解释为什么这个题目要用的是有向图的强连通的求法,而不是无向图的求法。
#include <stdio.h> #include <string.h> #include <vector> #include <algorithm> #define N 4005 using namespace std; int mat[N]; vector<int>gra[N],ans; int low[N],dfn[N],gid[N],now,id,mark[N]; vector<int>st; int n,a,b,c; void dfs(int s) { low[s]=dfn[s]=++now; st.push_back(s); mark[s]=1; for(int i=0;i<gra[s].size();i++) { int t=gra[s][i]; if(!dfn[t]) { dfs(t); low[s]=min(low[s],low[t]); } else if(mark[t]) low[s]=min(dfn[t],low[s]); } if(dfn[s]==low[s]) { id++; while(st.empty()==0) { int k=st.back(); gid[k]=id; st.pop_back(); mark[k]=0; if(k==s)break; } } } void re(void) { scanf("%d",&n); for(int i=1;i<=n*2;i++) gra[i].clear(); for(int i=1;i<=n;i++) { int m,k; scanf("%d",&m); for(int j=1;j<=m;j++) { scanf("%d",&k); gra[i].push_back(k+n); } } for(int i=1;i<=n;i++) { int k; scanf("%d",&k); mat[i]=k+n; mat[k+n]=i; gra[k+n].push_back(i); } } void run(void) { memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(gid,0,sizeof(gid)); memset(mark,0,sizeof(mark)); st.clear(); now=0;id=0; for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); for(int i=1;i<=n;i++) { ans.clear(); for(int j=0;j<gra[i].size();j++) if(gid[i]==gid[gra[i][j]]) ans.push_back(gra[i][j]-n); sort(&ans[0],&ans[0]+ans.size()); printf("%d",ans.size()); for(int j=0;j<ans.size();j++) printf(" %d",ans[j]); puts(""); } } int main() { re(); run(); return 0; }