思路
无非就两种情况:可二涂色或者存在奇环。
那么我们在dfs的过程中留意有无涂色不符的情况,
没有发现就直接输出一种涂色方案就行了。
现在问题就是找到奇环该怎么输出呢?
因为我是个笨比所以一开始写了个tarjan记录SCC,
然后去输出第一个奇数并大于1个点的SCC的每一个点编号,
结果只过了45.45%(所以看代码的时候请忽略没删的多余变量吧)
实际上我们对一个点访问第二次的时候发现它涂色不符,就
可以确定我们前面遍历了一个环,而这个环就是奇环,并且在栈中是连续的。
我们只需要按照入栈顺序进行输出即可。(写了tarjan还是有所启发的)
代码
#include<bits/stdc++.h> using namespace std; const int maxn=300007; int n,m,u,v,flag; int head[maxn],cnt; int col[maxn],vis[maxn]; int dfn[maxn],low[maxn],sz[maxn],bel[maxn]; int stk[maxn],top,idx,sccnum; vector<int>scc[maxn]; struct E{ int next,to; }e[maxn<<1]; void addedge(int from,int to){ e[++cnt].next=head[from]; e[cnt].to=to; head[from]=cnt; } void dfs(int x,int fa,bool c){ if(dfn[x]){ //已经访问过该节点 if(dfn[x]<top&&col[x]!=c){ //如果在栈中并且颜色不符 printf("%d\n",top-dfn[x]+1); for(int i=dfn[x];i<=top;i++) printf("%d ",stk[i]); exit(0); } return; } stk[++top]=x,dfn[x]=top; //入栈,用桶存栈下标 col[x]=c; for(int i=head[x];i;i=e[i].next){ if(e[i].to!=fa){ dfs(e[i].to,x,!c); } } --top; } signed main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n>>m; for(int i=1;i<=m;i++){ cin>>u>>v; addedge(u,v); addedge(v,u); } dfs(1,0,0); cout<<0<<endl; for(int i=1;i<=n;i++) cout<<col[i]<<" "; return 0; }