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;
}

Light OJ 1168 Wishing Snake 强连通缩点+哈密顿通路,布布扣,bubuko.com

时间: 2024-12-26 12:40:07

Light OJ 1168 Wishing Snake 强连通缩点+哈密顿通路的相关文章

Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖

题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 这里可能有环 所以要缩点 可是看例子又发现 一个强连通分量可能要拆分 n最大才15 所以就状态压缩 将全图分成一个个子状态 每一个子状态缩点 求最小路径覆盖 这样就攻克了一个强连通分量拆分的问题 最后状态压缩DP求解最优值 #include <cstdio> #include <cstri

Light OJ 1429 Assassin`s Creed (II) BFS+缩点+最小路径覆盖

题目来源:Light OJ 1429 Assassin`s Creed (II) 题意:最少几个人走完全图 可以重复走 有向图 思路:如果是DAG图并且每个点不能重复走 那么就是裸的最小路径覆盖 现在不是DAG 可能有环 并且每个点可能重复走 对于有环 可以缩点 缩点之后的图是DAG图 另外点可以重复走和POJ 2594一样 先预处理连通性 #include <cstdio> #include <cstring> #include <vector> #include &

Light OJ 1291 Real Life Traffic 双连通最少添边数

题目来源:Light OJ 1291 Real Life Traffic 题意:最少添加几条边 可以使全图边双连通 思路:缩点 重新构图 答案就是(叶子节点数+1)/ 2 #include <vector> #include <cstdio> #include <cstring> #include <stack> #include <algorithm> using namespace std; const int maxn = 10010; s

light oj 1236 【大数分解】

给定一个大数,分解质因数,每个质因子的个数为e1,e2,e3,--em, 则结果为((1+2*e1)*(1+2*e2)--(1+2*em)+1)/2. //light oj 1236 大数分解素因子 #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <math.h> #include <ctype.h> #i

[2016-04-21][light]OJ[1234][Harmonic Number]

时间:2016-04-21 22:18:26 星期四 题目编号:[2016-04-21][light]OJ[1234][Harmonic Number] 题目大意:求∑nk=11kn∈(1,108),精确到10?8求∑k=1n1kn∈(1,108),精确到10?8 分析: 想法是打表,然后输出,但是直接打表会爆内存 解决办法,就是每隔100个来打表,节省1100的空间,然后从那个值开始计算到当前值解决办法,就是每隔100个来打表,节省1100的空间,然后从那个值开始计算到当前值 对应的整百就是n

Light OJ 1411 Rip Van Winkle`s Code 线段树成段更新

题目来源:Light OJ 1411 Rip Van Winkle`s Code 题意:3中操作 1种查询 求区间和 其中每次可以把一段区间从左到右加上1,2,3,...或者从右到左加上...3,2,1 或者把某个区间的数都置为v 思路:我是加了6个域 add是这段区间每个数都要加上add  add是这么来的 对与123456...这个等差数列 可能要分为2个区间 那么我就分成123和123 两个右边的等差数列每个数还应该加上3 所以右区间add加3 v是这个区间都要置为v 他的优先级最高 b是

强连通缩点— HDU1827

强连通缩点以后最终形成的是一棵树 我们可以根据树的性质来看缩点以后的强连通分量图,就很好理解了 /* gyt Live up to every day */ #include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<stack> #include<cstring> #include<

Jan&#39;s light oj 01--二分搜索篇

碰到的一般题型:1.准确值二分查找,或者三分查找(类似二次函数的模型). 2.与计算几何相结合答案精度要求比较高的二分查找,有时与圆有关系时需要用到反三角函数利用 角度解题. 3.不好直接求解的一类计数问题,利用二分直接枚举可能的结果,再检查是否符合题目要求. 4.区间求解,即利用两次二分分别查找有序序列左右上下限,再求差算出总个数. 题型知识补充: 1. 三分的一般写法: 1 double thfind(double left,double right) 2 { 3 double midmid

light oj 1422 - Halloween Costumes (区间dp)

1422 - Halloween Costumes PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Gappu has a very busy weekend ahead of him. Because, next weekend is Halloween, and he is planning to attend as many parties as he can. Since it's Ha