Google Codejam 2016 Round1A Problem C BFFs 简单图论

链接

Google Codejam 2016 Round1A Problem C BFFs

题意

n个小朋友要坐成一个圈。每个小朋友心中都有一个Best Friend Forever。要保证每个人的左右至少有一个是他的BFF,问最多能让多少人做成一个圈。

思路

n只有1000,每个点的出度也都是1。看上去就不需要套用某种算法。综合的考虑一下,如果有m个人的BFF关系正好形成一个环,那么他们就可以成为一种结果,并且这个环中不能有别的人插入了。另外一种情况就是一条链,在这条链中有至少两个点A和B的BFF关系是相互的,A侧的人的关系依次指向A,B侧依次指向B,那么这条链也是可以成为结果,并且可以有多条这样的链构成最够的答案。
所以方法就是先求环的最大值,再累加出链的最大值。

代码

#include <bits/stdc++.h>

#define LL long long
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN 1005
using namespace std;


bool vis[MAXN][MAXN], mp[MAXN];
int cnt[MAXN];
int a[MAXN], d[MAXN];
int main(){
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
	int T;
	scanf("%d", &T);
	int cas = 0;
	while (T--){
		int n;
		scanf("%d", &n);
		for (int i = 1; i <= n; ++i){
			scanf("%d", &a[i]);
		}
		memset(cnt, 0, sizeof(cnt));
		memset(d, 0, sizeof(d));
		int ans = 0;
		for (int i = 1; i <= n; ++i){
			memset(mp, 0, sizeof(mp));
			int x = i;
			mp[x] = true;
			while (true){
				x = a[x];
				if (mp[x]) break;
				mp[x] = true;
				++cnt[i];
			}
			if (x == i){
				ans = max(ans, cnt[i] + 1);
			}
		}
		for (int i = 1; i <= n; ++i){
			for (int j = 1; j <= n; ++j){
				if (a[a[j]] == j) continue;
				d[a[j]] = max(d[a[j]], d[j] + 1);
			}
		}
		int res = 0;
		for (int i = 1; i <= n; ++i){
			if (a[a[i]] != i) continue;
			res += d[i] + d[a[i]] + 2;
		}
		res >>= 1;
		ans = max(ans, res);
		printf("Case #%d: %d
", ++cas, ans);
	}
}