【DG特长生2019 T3】【SSL 2891】【luogu P2661】【SSL 2505】游戏 / 信息传递(三种做法)

52 篇文章 1 订阅
27 篇文章 0 订阅

游戏 / 信息传递

题目链接:SSL 2891 / luogu P2661 / SSL 2505

题目大意

给你一个有向图,n 个点 n 条边,问你最小的环是多大。

思路

你就直接用并查集来搞,加多维护一个点到这个并查集的长度。

当然,你也可以直接用 Tarjan 或者 dfs 等多种方法来搞。
不过 SSL 的网上似乎会爆栈(luogu 不会),然后就不能用 dfs 搜的样子。

然后我就写了三种做法。。。

代码

#include<cstdio>
#include<iostream>

using namespace std;

int fa[200001], dis[200001], n;
int ans = 1e8, t;

int find(int now) {
	if (fa[now] == now) return now;
	int father = fa[now];
	fa[now] = find(fa[now]);
	dis[now] += dis[father];
	return fa[now];
}

void connect(int x, int y) {
	int X = find(x), Y = find(y);
	if (X == Y) ans = min(ans, dis[x] + dis[y] + 1);
		else {
			fa[X] = Y;
			dis[x] = dis[y] + 1;
		}
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		fa[i] = i;
	
	for (int i = 1; i <= n; i++) {
		scanf("%d", &t);
		connect(i, t);
	}
	
	printf("%d", ans);
	
	return 0;
}

不能在SSL上过的带有 dfs 的代码(tarjan)

#include<cstdio>
#include<iostream>

using namespace std;

struct node {
	int to, nxt;
}e[400001];
int n, y, le[200001], KK, ans = 1e8, tmp, num;
int dfn[200001], low[200001], in[200001], big[200001], sta[200001];

void add(int x, int y) {
	e[++KK] = (node){y, le[x]}; le[x] = KK;
}

void tarjan(int now) {
	dfn[now] = low[now] = ++tmp;
	sta[++sta[0]] = now;
	
	for (int i = le[now]; i; i = e[i].nxt)
		if (!dfn[e[i].to]) {
			tarjan(e[i].to);
			low[now] = min(low[now], low[e[i].to]);
		}
		else if (!in[e[i].to]) low[now] = min(low[now], dfn[e[i].to]);

	if (dfn[now] == low[now]) {
		in[now] = ++num;
		big[num] = 1;
		while (sta[sta[0]] != now) {
			in[sta[sta[0]]] = num;
			big[num]++;
			sta[0]--;
		}
		sta[0]--;
		if (big[num] != 1) ans = min(ans, big[num]);
	}
}

int main() {
//	freopen("game.in", "r", stdin);
//	freopen("game.out", "w", stdout);
	
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &y);
		add(i, y);
	}
	
	for (int i = 1; i <= n; i++)
		if (!dfn[i]) tarjan(i);
	
	printf("%d", ans);
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}

不能在SSL上过的带有 dfs 的代码(dfs 硬搜)

#include<cstdio>
#include<iostream>

using namespace std;
//
//struct node {
//	int to, nxt;
//}e[400001];
int n, y, le[200001], KK, answer = 1e8, tmp, num;
//int dfn[200001], low[200001], in[200001], big[200001], sta[200001];
int ans[200001], deg[200001], to[200001];

//void add(int x, int y) {
//	e[++KK] = (node){y, le[x]}; le[x] = KK;
//}

//void tarjan(int now) {
//	dfn[now] = low[now] = ++tmp;
//	sta[++sta[0]] = now;
//	
//	for (int i = le[now]; i; i = e[i].nxt)
//		if (!dfn[e[i].to]) {
//			tarjan(e[i].to);
//			low[now] = min(low[now], low[e[i].to]);
//		}
//		else if (!in[e[i].to]) low[now] = min(low[now], dfn[e[i].to]);
//
//	if (dfn[now] == low[now]) {
//		in[now] = ++num;
//		big[num] = 1;
//		while (sta[sta[0]] != now) {
//			in[sta[sta[0]]] = num;
//			big[num]++;
//			sta[0]--;
//		}
//		sta[0]--;
//		if (big[num] != 1) ans = min(ans, big[num]);
//	}
//}

void dfs(int now, int father) {
	if (ans[now]) return ;
	if (deg[now]) {
		ans[now] = deg[now] = deg[father];
		dfs(to[now], now);
		return ;
	}
	if (!ans[to[now]] && deg[to[now]]) {
		deg[now] = deg[father] + 2 - deg[to[now]];
		dfs(to[now], now);
		return ;
	}
	deg[now] = deg[father] + 1;
	dfs(to[now], now);
	if (!ans[now]) ans[now] = ans[to[now]] + 1;
}

int main() {
//	freopen("game.in", "r", stdin);
//	freopen("game.out", "w", stdout);
	
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &y);
//		add(i, y);
		to[i] = y;
	}
	
//	for (int i = 1; i <= n; i++)
//		if (!dfn[i]) tarjan(i);
	for (int i = 1; i <= n; i++) {
		dfs(i, i);
		answer = min(answer, ans[i]);
	}
	
	printf("%d", answer);
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值