Codeforces 1144 F 图的着色

http://codeforces.com/problemset/problem/1144/F

You are given a connected undirected graph consisting of nn vertices and mm edges. There are no self-loops or multiple edges in the given graph.

You have to direct its edges in such a way that the obtained directed graph does not contain any paths of length two or greater (where the length of path is denoted as the number of traversed edges).

Input

The first line contains two integer numbers nn and mm (2≤n≤2⋅1052≤n≤2⋅105 , n−1≤m≤2⋅105n−1≤m≤2⋅105 ) — the number of vertices and edges, respectively.

The following mm lines contain edges: edge ii is given as a pair of vertices uiui , vivi (1≤ui,vi≤n1≤ui,vi≤n , ui≠viui≠vi ). There are no multiple edges in the given graph, i. e. for each pair (ui,viui,vi ) there are no other pairs (ui,viui,vi ) and (vi,uivi,ui ) in the list of edges. It is also guaranteed that the given graph is connected (there is a path between any pair of vertex in the given graph).

Output

If it is impossible to direct edges of the given graph in such a way that the obtained directed graph does not contain paths of length at least two, print "NO" in the first line.

Otherwise print "YES" in the first line, and then print any suitable orientation of edges: a binary string (the string consisting only of '0' and '1') of length mm . The ii -th element of this string should be '0' if the ii -th edge of the graph should be directed from uiui to vivi , and '1' otherwise. Edges are numbered in the order they are given in the input.

Example

Input

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

Output

YES
10100

题目大意: 给一个无向图,让你给每条边确定一个方向,使得整个图中没有长度大于等于2的路径存在,如果可以输出"YES"并输出该方案,否则输出"NO"。

思路: 其实就是图的着色问题。 只用两种颜色给图着色, 使得相邻两个顶点的颜色均不相同。 颜色可以自己指定,比如1意味着与该点相邻的边是指向其他点的,2意味着与该点相邻的边是指向该点的,然后就可以dfs进行判断了。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#include<cstring>
using namespace std;

struct edge //链式前向星
{
	int to,next;
};

edge e[400005];
int head[200005];
int vis[200005];
int n,m;
int flag;

void dfs(int cur,int tag)
{
	if(flag)
		return ;
	if(!vis[cur])//该点还没被染过色
		vis[cur]=tag;
	else
	{
		if(vis[cur]!=tag)//若该点已经被染过色 但是现在要染别的颜色 不符题意
			flag=1;
		return ;
	}
	for(int i=head[cur];i!=0;i=e[i].next)//访问相邻结点
	{
		if(tag==1)
			dfs(e[i].to,2);
		else
			dfs(e[i].to,1);
	}
}

int main()
{
	scanf("%d %d",&n,&m);
	int t1,t2;
	for(int i=1;i<=2*m;i+=2)
	{
		scanf("%d %d",&t1,&t2);
		e[i].to=t2;
		e[i].next=head[t1];
		head[t1]=i;
		e[i+1].to=t1;
		e[i+1].next=head[t2];
		head[t2]=i+1;
	}
	dfs(1,1);
	if(flag)
		printf("NO\n");
	else
	{
		printf("YES\n");
		for(int i=1;i<=2*m;i+=2)
		{
			if(vis[e[i].to]==1)
				printf("1");
			else
				printf("0");
		}
	}
	return 0;
}

另外一种思路: 用map记录题目给定的路径, 然后在dfs的时候进行判断。(效率要慢)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#include<cstring>
using namespace std;
typedef pair<int,int> P;

int vis[200005];
vector<int> vec[200005];
map<P,int> my;
int re[200005];
int n,m;
int flag=0;

void dfs(int cur,int tag)//tag自己定义 比如tag=0 方向是从该点到其他点 tag=1 方向是从其他点到该点
{
	if(flag)
		return ;
	if(vis[cur])
		return ;
	vis[cur]=1;
	P p;
	int temp;
	for(int i=0;i<vec[cur].size();i++)
	{
		if(tag==0)//cur->vec[cur][i]
		{
			p.first=cur,p.second=vec[cur][i];
			if(my.count(p))//跟输入一致
			{
				temp=my[p];
				if(re[temp]==2)
					flag=1;
				re[temp]=1;
			}
			else//跟输入不一致
			{
				swap(p.first,p.second);
				temp=my[p];
				if(re[temp]==1)
					flag=1;
				re[temp]=2;
			}
			dfs(vec[cur][i],1);
		}
		else //vec[cur][i]->cur
		{
			p.first=vec[cur][i],p.second=cur;
			if(my.count(p))//跟输入一致
			{
				temp=my[p];
				if(re[temp]==2)
					flag=1;
				re[temp]=1;
			}
			else//跟输入不一致
			{
				swap(p.first,p.second);
				temp=my[p];
				if(re[temp]==1)
					flag=1;
				re[temp]=2;
			}
			dfs(vec[cur][i],0);
		}
	}
}

int main()
{
	scanf("%d %d",&n,&m);
	int t1,t2;
	P p;
	for(int i=0;i<m;i++)
	{
		scanf("%d %d",&t1,&t2);
		vec[t1].push_back(t2);
		vec[t2].push_back(t1);
		p.first=t1,p.second=t2;
		my[p]=i;
	}
	dfs(t1,0);
	if(flag)
		printf("NO\n");
	else
	{
		printf("YES\n");
		for(int i=0;i<m;i++)
			printf("%d",re[i]-1);
		printf("\n");
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值