CF760 C. Pavel and barbecue 简单DFS

LINK

题意:给出n个数,(a_i)代表下一步会移动到第(a_i)个位置,并继续进行操作,(b_i)1代表进行一次翻面操作,要求不管以哪个位置上开始,最后都能满足

1.到达过所有位置

2.对到达的任意位置,都已经进行过奇次和偶次翻面操作

交换任意两个(a_i),或修改(b_i)的值算做一次操作

问最小操作数。

思路:首先可以知道,要满足条件1,必须使该排列的循环节长度为1(即所有数成一个环),再者要满足条件2,则(b_i==1)必须有奇数个。

那么很简单,对所有未标记的数dfs一遍,进行的dfs次数就是循环节长度,再统计(b_i)中1的个数即可。

/** @Date    : 2017-04-09 21:10:36
  * @FileName: 760C DFS.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoundEarlf@gmail.com)
  * @Link    : https://github.com/Lweleth
  * @Version : $Id$
  */
#include<bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 2e5+20;
const double eps = 1e-8;

int a[N], b[N];
int vis[N];
void dfs(int x)
{
	vis[x] = 1;
	if(vis[a[x]] == 0)
		dfs(a[x]);
}

int main()
{
	int n;
	while(cin >> n)
	{
		MMF(vis);
		for(int i = 1; i <= n; i++)
			scanf("%d", a + i);
		for(int i = 1; i <= n; i++)
			scanf("%d", b + i);
		int ans = 0;
		int cnt = 0;
		for(int i = 1; i <= n; i++)
		{
			if(!vis[i])
				dfs(i), ans++;
			if(b[i])
				cnt++;
		}
		if(ans == 1)
			ans--;
		printf("%d
", ans + ((cnt%2)?0:1));
	}
    return 0;
}

原文地址:https://www.cnblogs.com/Yumesenya/p/6728529.html