首页 > 代码库 > Light OJ 1168 Wishing Snake 强连通缩点+哈密顿通路

Light OJ 1168 Wishing Snake 强连通缩点+哈密顿通路

题目来源:Light OJ 1168 Wishing Snake

题意:有点难看懂题意 看了一个小时再加别人的代码才懂意思 

从0开始 输入的那些每一对u v 都要经过 就是从0到到达那些点

思路:首先缩点 每一个强连通分量里面的点都是可达的 

缩点后的图是有向无环图 如果从0这个强连通分量可以出去到2个强连通分量 那么这两个强连通分量是不可能相互可达

所以可行的方案就是所有的强连通分量连成一线 一个一个串起来 除了第一个 出度是1入度是0和最后一个出度是0入度是1 其他都是入度等于出度是1 

特判只有一个强连通分量 和 开始第一个强连通分量是0所在的强连通分量


#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
const int maxn = 1010;

vector <int> G[maxn];
int pre[maxn];
int low[maxn];
int sccno[maxn];
int dfs_clock;
int scc_cnt;
stack <int> S;
int n, m;
int in[maxn];
int out[maxn];
int cnt[maxn];
int id[maxn];
void dfs(int u)
{
	pre[u] = low[u] = ++dfs_clock;
	S.push(u);
	for(int i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i];
		if(!pre[v])
		{
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if(!sccno[v])
			low[u] = min(low[u], pre[v]);
	}
	if(pre[u] == low[u])
	{
		scc_cnt++;
		while(1)
		{
			cnt[scc_cnt]++;
			int x = S.top();
			S.pop();
			sccno[x] = scc_cnt;
			if(x == u)
				break;
		}
	}
}
void find_scc()
{
	dfs_clock = scc_cnt = 0;
	memset(sccno, 0, sizeof(sccno));
	memset(pre, 0, sizeof(pre));
	memset(cnt, 0, sizeof(cnt));
	for(int i = 0; i <= n; i++)
		if(!pre[i])
			dfs(i);
}
int main()
{
	int cas = 1;
	int T;
	scanf("%d", &T);
	while(T--)
	{
		memset(id, -1, sizeof(id));
		scanf("%d", &m);
		for(int i = 0; i <= 1000; i++)
			G[i].clear();
		n = 0;
		id[0] = 0;
		while(m--)
		{
			int k;
			scanf("%d", &k);
			while(k--)
			{
				int u, v;
				scanf("%d %d", &u, &v);
				if(id[u] == -1)
					id[u] = ++n;
				if(id[v] == -1)
					id[v] = ++n;		
				G[id[u]].push_back(id[v]);
			}
		}
		find_scc();
		memset(in, 0, sizeof(in));
		memset(out, 0, sizeof(out));
		for(int i = 0; i <= n; i++)
		{
			for(int j = 0; j < G[i].size(); j++)
			{
				int v = G[i][j];
				if(sccno[i] != sccno[v])
				{
					in[sccno[v]]++;
					out[sccno[i]]++;
				}
			}
		}
		if(scc_cnt == 1)
		{
			printf("Case %d: YES\n", cas++);
			continue;
		}
		if(in[sccno[0]] != 0 || out[sccno[0]] == 0)
		{
			printf("Case %d: NO\n", cas++);
			continue;
		}
		
		int sum1 = 0, sum2 = 0, sum3 = 0;
		for(int i = 1; i <= scc_cnt; i++)
		{
			if(in[i] == 1 && out[i] == 1)
				sum1++;
			else if(in[i] == 1 && out[i] == 0)
				sum2++;
			else if(in[i] == 0 && out[i] == 1)
				sum3++;
		}
		if(sum2 != 1 || sum3 != 1 || sum1+sum2+sum3 != scc_cnt)
			printf("Case %d: NO\n", cas++);
		else
			printf("Case %d: YES\n", cas++);
	}
	return 0;
}