[BZOJ 4436][Cerc2015]Kernel Knights

[Cerc2015]Kernel Knights

Time Limit: 2 Sec Memory Limit: 512 MB
Submit: 5 Solved: 4
[Submit][Status][Discuss]
Description

“Jousting”是一种让骑士在高速骑行中用木制长矛相互攻击对方的中世纪竞技游戏。现在,一共有2n个骑士进入一场“Jousting”锦标赛。骑士们被平均分配到2个house。竞赛开始时,所有骑士都会对另一个house的骑士之一发起挑战。
一组解被定义为一个集合S满足:

• S中的骑士不存在相互挑战。
• 所有不在S中的骑士都被S中的骑士挑战。

现给出官方公布的挑战场次,找出一组解。
数据保证有解。

Input

第一行包括一个整数n(1<=n<=100000)——每个house的骑士数。第一个house的骑士编号为1~n,第二个house的骑士编号为n+1~2n。
接下来一行包含n个整数f1,f2,…,fn——fk指第k名骑士发起的挑战。
最后一行包含n个整数s1,s2,…,sn——sk指第n+k名骑士发起的挑战。
(1<=fk,sk<=n)

Output

在一行中输出S中骑士的编号。
如果数据存在多组解,你只需任意输出一组。

Sample Input

4

5 6 7 7

1 3 2 3
Sample Output

1 2 4 8

HINT 请不要提交,期待SPJ

 

因为原图是二分图,所以所有的环都是偶环

因为每个点只有一个出度,所以所有的环都是简单环。

那么这个图可以想象成一个内向基环森林

每次给度为0的节点染色。每遍历到一个点度--

如果将要到达的点度为0或者它的颜色为不可选(因为此点不可选所以不能随便染色),那么继续遍历(博主语死早。。大家自行画图吧。。)

然后把所有没有标记的环搞一遍就可以了

 

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 500010
using namespace std;
int n;
int to[maxn], h[maxn], cnt, deg[maxn], col[maxn];
void add(int u, int v){to[u] = v, deg[v] ++;}

void BFS(int u){
	col[u] = 2;
	while(true){
		if(col[to[u]])break;
		deg[to[u]] --;
		if(deg[to[u]] == 0 || col[u] == 2){
            col[to[u]] = col[u] ^ 1;
			u = to[u];
		}
		else break;
	}
}

void Col(int u){
	col[u] = 2;
	while(true){
		if(col[to[u]])break;
		col[to[u]] = col[u] ^ 1;
		u = to[u];
	}
}

int main(){
    scanf("%d", &n);
    int v;
    for(int i = 1; i <= n; i ++)
        scanf("%d", &v), add(i, v);

    for(int i = n + 1; i <= n * 2; i ++)
        scanf("%d", &v), add(i, v);
	n <<= 1;
	for(int i = 1; i <= n; i ++)
	    if(!deg[i] && !col[i])BFS(i);
    for(int i = 1; i <= n; i ++)
        if(!col[i])Col(i);
	for(int i = 1; i <= n; i ++)
	    if(col[i] == 2)printf("%d ", i);
    return 0;
}

  

posted @ 2016-05-16 19:54  _Horizon  阅读(377)  评论(0编辑  收藏  举报