Description
给出一个n个顶点的有向图(无重边),现要给每条边染色1或2,问是否存在一种染色方案使得每个顶点所连的边中两种颜色都有(如果某点度数小于2则不考虑)
Input
第一行为一整数n表示点数,之后n行每行表示一个点的邻接表,以0结束每行的输入
Output
如果存在一个合法的染色方案,则按输入顺序输出每条边应该染的颜色,否则输出No solution
Sample Input
6
2 3 0
1 3 0
1 2 5 0
5 0
4 6 3 0
5 0
Sample Output
1 2 0
1 2 0
2 2 1 0
2 0
2 2 1 0
2 0
Solution
考虑顶点的度数
如果一个点是奇度顶点(只考虑度数不小于2的,因为小于2的顶点不会影响染色方案的存在),那么从这个点开始dfs交叉染色会出现两种情况:第一种情况是经过一条环后回到该点,此时这个环除该点外一定全部满足条件了(染色是交叉的),而该点就算不满足条件,由于其是奇度顶点且度数不小于2,则必然可以从与该点相连的另一条边开始染另一种颜色使得该点满足条件;第二种情况是没有环,同样的,下一次可以从与这个奇度顶点相连的另一条边开始染另一种颜色。故奇度顶点一定可以满足条件。
如果一个点是偶度顶点,同样的,从这个点开始染色会有和奇度顶点一样的两种情况,其中第二种情况可以满足条件,即从这个偶度顶点开始染色如果不成环则可以从与这个偶度顶点相连的另一条边开始染另一种颜色;但是如果成环且成的是奇环且这个顶点的度数是2,这个偶度顶点就不满足条件。
通过上面的分析可以看出,首先从奇度顶点开始染色更优,因为这样不仅可以让奇度顶点满足条件而且并不会影响偶度顶点的染色
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define maxn 111
vector<int>g[maxn];
int n,degree[maxn],mark[maxn][2],ans[maxn][maxn];
void init()
{
for(int i=1;i<=n;i++)g[i].clear();
memset(degree,0,sizeof(degree));
memset(mark,0,sizeof(mark));
memset(ans,-1,sizeof(ans));
}
void dfs(int u,int cur)
{
cur^=1;
for(int i=0;i<degree[u];i++)
if(ans[u][g[u][i]]==-1)
{
ans[u][g[u][i]]=ans[g[u][i]][u]=cur;
mark[u][cur]=mark[g[u][i]][cur]=1;
dfs(g[u][i],cur);
cur^=1;
}
}
int main()
{
while(~scanf("%d",&n))
{
init();
for(int i=1;i<=n;i++)
{
int temp;
while(scanf("%d",&temp),temp)
g[i].push_back(temp),degree[temp]++;
}
for(int i=1;i<=n;i++)
if(degree[i]&1)dfs(i,0);
for(int i=1;i<=n;i++)dfs(i,0);
int flag=1;
for(int i=1;i<=n;i++)
if((!mark[i][0]||!mark[i][1])&°ree[i]>1)
{
flag=0;
break;
}
if(flag)
for(int i=1;i<=n;i++)
{
for(int j=0;j<g[i].size();j++)
printf("%d ",ans[i][g[i][j]]+1);
printf("0\n");
}
else printf("No solution\n");
}
return 0;
}