[BZOJ]1064 [NOI2008] 假面舞会 dfs判环

1064: [Noi2008]假面舞会

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 2160   Solved: 1047
[ Submit][ Status][ Discuss]

Description

一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会。今年的面具都是主办方特别定制的。每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具。每个面具都有一个编号,主办方会把此编号告诉拿该面具的人。为了使舞会更有神秘感,主办方把面具分为k (k≥3)类,并使用特殊的技术将每个面具的编号标在了面具上,只有戴第i 类面具的人才能看到戴第i+1 类面具的人的编号,戴第k 类面具的人能看到戴第1 类面具的人的编号。 参加舞会的人并不知道有多少类面具,但是栋栋对此却特别好奇,他想自己算出有多少类面具,于是他开始在人群中收集信息。 栋栋收集的信息都是戴第几号面具的人看到了第几号面具的编号。如戴第2号面具的人看到了第5 号面具的编号。栋栋自己也会看到一些编号,他也会根据自己的面具编号把信息补充进去。由于并不是每个人都能记住自己所看到的全部编号,因此,栋栋收集的信 息不能保证其完整性。现在请你计算,按照栋栋目前得到的信息,至多和至少有多少类面具。由于主办方已经声明了k≥3,所以你必须将这条信息也考虑进去。

Input

第一行包含两个整数n, m,用一个空格分隔,n 表示主办方总共准备了多少个面具,m 表示栋栋收集了多少条信息。接下来m 行,每行为两个用空格分开的整数a, b,表示戴第a 号面具的人看到了第b 号面具的编号。相同的数对a, b 在输入文件中可能出现多次。

Output

包含两个数,第一个数为最大可能的面具类数,第二个数为最小可能的面具类数。如果无法将所有的面具分为至少3 类,使得这些信息都满足,则认为栋栋收集的信息有错误,输出两个-1。

Sample Input

【输入样例一】

6 5
1 2
2 3
3 4
4 1
3 5

【输入样例二】

3 3
1 2
2 1
2 3

Sample Output

【输出样例一】
4 4

【输出样例二】
-1 -1

HINT

100%的数据,满足n ≤ 100000, m ≤ 1000000。

Source

[ Submit][ Status][ Discuss]


HOME Back

题解:Click

#include<stdio.h>
#include<cmath>
#include<cstring>
#include<algorithm>
#define clear(a) memset(a, 0, sizeof(a))
using namespace std;
const int maxn = 200005;
int ans, n, m, num(1), mx, mn;
bool vis[maxn], mark[maxn * 20];
int dis[maxn], h[maxn];
struct edge{ int nxt, v, w;}e[maxn * 20];
inline void add(int u, int v, int w){
	e[++num].v = v, e[num].nxt= h[u], e[num].w = w, h[u] = num;
}
int gcd(int a, int b){
	return (!b) ? a : gcd(b, a % b);
}
void dfs_chain(int u){
	mx = max(mx, dis[u]);
	mn = min(mn, dis[u]);
	vis[u] = true;
	for(int i = h[u]; i; i = e[i].nxt)
		if(!mark[i]){
			mark[i] = mark[i ^ 1] = true;
			int v = e[i].v;
			dis[v] = dis[u] + e[i].w, dfs_chain(v);
		}
}
void dfs_cir(int u){
	vis[u] = true;
	for(int i = h[u]; i; i = e[i].nxt){
		int v = e[i].v;
		if(vis[v]) ans = gcd(ans, abs(dis[u] + e[i].w - dis[v]));
		else dis[v] = dis[u] + e[i].w, dfs_cir(v);
	}
}
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; ++i){
		int x, y;
		scanf("%d%d", &x, &y);
		add(x, y, +1), add(y, x, -1);
	}
	for(int i = 1; i <= n; ++i)
		if(!vis[i]) dfs_cir(i);
	if(ans){
		if(ans < 3) puts("-1 -1");
		else{
			for(int i = 3; i <= ans; ++i)
				if(!(ans % i)){
					printf("%d %d\n", ans, i);
					break;
				}
		}
		return 0;
	}
	clear(vis);
	for(int i = 1; i <= n; ++i)
		if(!vis[i]){
			mx = mn = dis[i] = 0;
			dfs_chain(i);
			ans += mx - mn + 1;
		}
	if(ans < 3) puts("-1 -1");
	else printf("%d %d\n", ans, 3);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值