题解 回路

传送门

其实乱搞能过

正解(粘的题解):
每次从队头取出一个点 \(u\) 后,遍历它连向的所有节点 \(v\) ,若 \(u\) 已经在队列中且不是 \(v\) 的前驱
那么说明我们已经找到了一条非平凡回路,并且这一定是最短的。此时 \(u\) 的最短路 \(+1\) 就是答案
每个点最多入队一遍,因此是 \(O(n^2)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 5010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

int n;
char s[N];
vector<int> e[N];

namespace task1{
	queue<int> q;
	int back[N], dis[N], ans;
	void bfs(int s) {
		q.push(s);
		// int cnt=0;
		while (q.size()) {
			int u=q.front(); q.pop();
			// ++cnt;
			for (auto& v:e[u])
				if (dis[v]>dis[u]+1) {
					dis[v]=dis[u]+1;
					back[v]=u; q.push(v);
				}
				else if (v!=back[u]) ans=min(ans, dis[u]+dis[v]+1);
		}
		// cout<<"cnt: "<<cnt<<endl;
	}
	void solve() {
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			memset(dis, 0x3f, sizeof(dis));
			memset(back, -1, sizeof(back));
			dis[i]=0; ans=INF;
			bfs(i);
			printf("%d\n", ans==INF?-1:(ans+1)/2);
		}
	}
}

namespace task2{
	queue<int> q;
	int back[N], dis[N], ans;
	void bfs(int s) {
		q.push(s);
		// int cnt=0;
		while (q.size()) {
			int u=q.front(); q.pop();
			// ++cnt;
			if (2*dis[u]>=ans) continue;
			if (ans==3) continue;
			for (auto& v:e[u])
				if (dis[v]>dis[u]+1) {
					dis[v]=dis[u]+1;
					back[v]=u; q.push(v);
				}
				else if (v!=back[u]) ans=min(ans, dis[u]+dis[v]+1);
		}
		// cout<<"cnt: "<<cnt<<endl;
	}
	void solve() {
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			memset(dis, 0x3f, sizeof(dis));
			memset(back, -1, sizeof(back));
			dis[i]=0; ans=INF;
			bfs(i);
			printf("%d\n", ans==INF?-1:(ans+1)/2);
		}
	}
}

signed main()
{
	freopen("a.in", "r", stdin);
	freopen("a.out", "w", stdout);

	scanf("%d", &n);
	for (int i=2; i<=n; ++i) {
		scanf("%s", s+1);
		for (int j=1; j<i; ++j) if (s[j]=='1')
			e[i].pb(j), e[j].pb(i);
	}
	if (n<=200) task1::solve();
	else task2::solve();

	return 0;
}
posted @ 2022-04-09 20:21  Administrator-09  阅读(2)  评论(0编辑  收藏  举报