bzoj 1064: [Noi2008]假面舞会(DFS)

1064: [Noi2008]假面舞会

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 2240   Solved: 1083
[ 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


这题题意可以转换成染色问题:

对于每个节点,它的所有后继颜色必须全部相同,并且不能和它相同

例如样1->2,1->3,那么2和3的颜色必须一样,且1和2,1和3的颜色必须不一样

按上面的条件给所有点染色,问最多可以用多少种颜色,最少要用多少种颜色(>=3)

如果最多可以用的颜色数量<3,输出-1 -1


结论:

先将图处理一下,所有的边权值设为1,然后把它转成无向图,反向边的权值设为-1

两种情况:

①如果无向图中存在环:

colmax = 所有环边权和的最大公约数,colmin = 所有环边权和的最小公约数(要求>=3)

②无向图中不存在环:

找到每个连通图的最长权值链,加在一起就是colmax,colmin = 3


#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
#include<stdlib.h>
using namespace std;
vector<int> G[100005], GF[100005];
queue<int> q;
int bet, vis[100005], len[100005], in[100005], dp[100005], ans;
int Gcd(int x, int y)
{
	if(x==0)  return y;
	if(y==0)  return x;
	return Gcd(y, x%y);
}
void Sech(int u, int val)
{
	int i, v;
	len[u] = val;
	vis[u] = 1;
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(vis[v]==0)
			Sech(v, val+1);
		else
			ans = Gcd(ans, abs(len[u]-len[v]+1));
	}
	for(i=0;i<GF[u].size();i++)
	{
		v = GF[u][i];
		if(vis[v]==0)
			Sech(v, val-1);
		else
			ans = Gcd(ans, abs(len[u]-len[v]-1));
	}
}
void Sech2(int u)
{
	int i, v;
	vis[u] = 1;
	bet = max(bet, dp[u]);
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(vis[v]==0)
			Sech2(v);
	}
	for(i=0;i<GF[u].size();i++)
	{
		v = GF[u][i];
		if(vis[v]==0)
			Sech2(v);
	}
}
int main(void)
{
	int i, j, x, y, n, m;
	//freopen("in.txt", "r", stdin);
	scanf("%d%d", &n, &m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d", &x, &y);
		G[x].push_back(y);
		GF[y].push_back(x);
		in[y]++;
	}
	for(i=1;i<=n;i++)
	{
		if(vis[i]==0)
			Sech(i, 0);
	}
	if(ans)
	{
		if(ans<3)
			printf("-1 -1\n");
		else
		{
			for(i=3;i<=ans;i++)
			{
				if(ans%i==0)
				{
					printf("%d %d\n", ans, i);
					break;
				}
			}
		}
	}
	else
	{
		memset(vis, 0, sizeof(vis));
		for(i=1;i<=n;i++)
		{
			if(in[i]==0)
			{
				dp[i] = 1;
				q.push(i);
				vis[i] = 1;
			}
		}
		while(q.empty()==0)
		{
			x = q.front();
			q.pop();
			vis[x] = 0;
			for(j=0;j<G[x].size();j++)
			{
				y = G[x][j];
				if(dp[x]+1>dp[y])
				{
					dp[y] = dp[x]+1;
					if(vis[y]==0)
					{
						vis[y] = 1;
						q.push(y);
					}
				}
			}
			for(j=0;j<GF[x].size();j++)
			{
				y = GF[x][j];
				if(dp[x]-1>dp[y])
				{
					dp[y] = dp[x]-1;
					if(vis[y]==0)
					{
						vis[y] = 1;
						q.push(y);
					}
				}
			}
		}
		for(i=1;i<=n;i++)
		{
			bet = 0;
			if(vis[i]==0)
				Sech2(i);
			ans += bet;
		}
		if(ans>=3)
			printf("%d 3\n", ans);
		else
			printf("-1 -1\n");
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值