poj 1904 tarjan强连通分量(给国王的2000个儿子找老婆 )
2015-04-15 21:03
141 查看
题意:有n个王子,每个王子i有ki个他喜欢的妹子,每个王子只能和喜欢的妹子结婚,大臣给出一个匹配表(假设肯定是对的),每个王子都和一个妹子结婚,但是国王不满意,他要求大臣给他另一个表,每个王子可以和几个妹子结婚,按序号升序输出妹子的编号,这个表应满足所有的王子最终都有妹子和他结婚。
思路:一开始自己想了一会儿只能想到是反复找匹配,连大臣给的初始匹配有什么用都不知道。后来看了题解(http://www.cnblogs.com/frog112111/p/3384261.html)才明白该怎么做,ORZ~
首先建图,如果王子u喜欢妹子v,则建一条边u指向v,即(u,v),对于大臣给出的初始完美匹配,如果王子u和妹子v结婚,则建一条边v指向u,即(v,u),然后求强连通分量。
对于每个王子和他喜欢的妹子,如果他们都在同一个强连通分量内,则他们一定可以结婚。
为什么呢?因为每个王子只能和喜欢的妹子结婚,初始完美匹配中的丈夫和妻子之间有两条方向不同的边可以互达,则同一个强连通分量中的王子数和妹子数一定是相等的。若王子x可以和另外的一个妹子a结婚,妹子a的原配王子y肯定能找到另外一个妹子b结婚。这个可以这样想:在他们所在的强连通分量中,去掉x和a这两个点以后,剩下的部分必然满足HALL条件:考虑妹子那部,任意子集的邻居至少有子集元素那么多个,所以完备匹配必然存在。
我挺好奇出题人是怎么想到这个性质的来出这道题的,太厉害了~~
思路:一开始自己想了一会儿只能想到是反复找匹配,连大臣给的初始匹配有什么用都不知道。后来看了题解(http://www.cnblogs.com/frog112111/p/3384261.html)才明白该怎么做,ORZ~
首先建图,如果王子u喜欢妹子v,则建一条边u指向v,即(u,v),对于大臣给出的初始完美匹配,如果王子u和妹子v结婚,则建一条边v指向u,即(v,u),然后求强连通分量。
对于每个王子和他喜欢的妹子,如果他们都在同一个强连通分量内,则他们一定可以结婚。
为什么呢?因为每个王子只能和喜欢的妹子结婚,初始完美匹配中的丈夫和妻子之间有两条方向不同的边可以互达,则同一个强连通分量中的王子数和妹子数一定是相等的。若王子x可以和另外的一个妹子a结婚,妹子a的原配王子y肯定能找到另外一个妹子b结婚。这个可以这样想:在他们所在的强连通分量中,去掉x和a这两个点以后,剩下的部分必然满足HALL条件:考虑妹子那部,任意子集的邻居至少有子集元素那么多个,所以完备匹配必然存在。
我挺好奇出题人是怎么想到这个性质的来出这道题的,太厉害了~~
#include <cstdio> #include <cstring> #include <algorithm> #define N 2005 using namespace std; struct edge{ int y,next; }e[200000+N*2]; int n,first[N<<1],top,len; int dfn[N<<1],low[N<<1],strong[N<<1],stack[N<<1],inst[N<<1],con,ind,st; void add(int x,int y){ e[top].y = y; e[top].next = first[x]; first[x] = top++; } void tarjan(int x){ int i,y; dfn[x] = low[x] = ++ind; stack[st++] = x; inst[x] = 1; for(i = first[x];i!=-1;i=e[i].next){ y = e[i].y; if(dfn[y] == -1){ tarjan(y); low[x] = min(low[x], low[y]); }else if(inst[y]) low[x] = min(low[x], dfn[y]); } if(dfn[x] == low[x]){ con++; do{ strong[stack[--st]] = con; inst[stack[st]] = 0; }while(stack[st] != x); } } int main(){ int i,j,num; scanf("%d",&n); top = con = ind = st = 0; memset(first, -1, sizeof(first)); memset(inst, 0, sizeof(inst)); memset(dfn, -1, sizeof(dfn)); for(i = 1;i<=n;i++){ scanf("%d",&num); while(num--){ scanf("%d",&j); add(i,j+n); } } for(i = 1;i<=n;i++){ scanf("%d",&j); add(j+n,i); //这个地方写反了WA了几次 } for(i = 1;i<=2*n;i++) if(dfn[i] == -1) tarjan(i); for(i = 1;i<=n;i++){ len = 0; for(j = first[i];j!=-1;j=e[j].next) if(strong[i] == strong[e[j].y]) dfn[len++] = e[j].y-n; sort(dfn,dfn+len); printf("%d",len); for(j = 0;j<len;j++) printf(" %d",dfn[j]); printf("\n"); } return 0; }
相关文章推荐
- POJ 1904(强连通分量)Tarjan
- poj 1904 强连通分量 tarjan
- King's Quest - poj 1904(强连通分量+外挂输入输出)
- POJ 1904 King's Quest (强连通分量)
- poj 2186 Popular Cows(强连通分量,tarjan或Kosaraju)
- POJ-2762 Going from u to v or from v to u? (强连通分量[Tarjan]&&(拓扑排序||树形DP))
- POJ-2553 The Bottom of a Graph (强连通分量[Tarjan])
- poj 1236 Network of Schools(强连通分量 Tarjan)
- poj 2186 tarjan求强连通分量(模板题)
- poj 3180 The Cow Prom 强连通分量tarjan
- POJ 1236 强连通分量 Tarjan
- poj 1904(强连通分量+输入输出外挂)
- POJ-3114 Countries in War (强连通分量[Tarjan]&&Dijkstra)
- [poj 1904]King's Quest[Tarjan强连通分量]
- POJ 1236 tarjan 算法求强连通分量
- POJ 2762 强连通分量 Tarjan + 缩点
- Poj 1904 King's Quest 强连通分量
- poj 1904 强连通分量
- POJ 1236 Network of Schools (强连通分量tarjan)
- POJ 2186 Popular Cows(Tarjan算法求强连通分量)