Description
给定 n 个点,m 条边的无向图,可以从图中删除一条边,问删除哪些边可以使图变成
一个二分图。
【题目分析】
手玩一下,发现删除的是奇环的交集,而且不在偶环上的点,然后乱搞就可以了。
【代码】
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <set>
#include <map>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue>
using namespace std;
#define maxn 1000005
#define inf (0x3f3f3f3f)
int read()
{
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int fr[maxn<<1],h[maxn],to[maxn<<1],ne[maxn<<1],en=0,ans[maxn<<1],intree[maxn<<1];
int n,m,f[maxn],dep[maxn],fa[maxn],can[maxn<<1];
int cov[maxn],tag[maxn],vis[maxn<<1],out[maxn];
void addedge(int a,int b)
{
fr[en]=a;
to[en]=b;
ne[en]=h[a];
h[a]=en++;
}
int gf(int k)
{
if (f[k]==k) return k;
else return f[k]=gf(f[k]);
}
void dfs(int k)
{
// printf("dfs on %d\n",k);
f[k]=k; vis[k]=1;
for (int i=h[k];i>=0;i=ne[i])
if (vis[to[i]])
ans[i]=ans[i^1]=gf(to[i]);
for (int i=h[k];i>=0;i=ne[i])
if (!vis[to[i]])
{
fa[to[i]]=i/2+1;
intree[i]=intree[i^1]=1;
dep[to[i]]=dep[k]+1;
dfs(to[i]);
f[to[i]]=k;
}
}
int dfs2(int k)
{
for (int i=h[k];i>=0;i=ne[i])
if (dep[to[i]]==dep[k]+1)
cov[k]+=dfs2(to[i]);
return cov[k];
}
int dfs3(int k)
{
for (int i=h[k];i>=0;i=ne[i])
if (dep[to[i]]==dep[k]+1)
tag[k]+=dfs3(to[i]);
return tag[k];
}
int main()
{
memset(h,-1,sizeof h);
n=read(); m=read();
for (int i=1;i<=m;++i)
{
int a,b;
a=read();b=read();
addedge(a,b);addedge(b,a);
}
for (int i=1;i<=n;++i)
if (!vis[i])
{
dfs(i);
f[i]=0;
fa[i]=-1;
}
int cnt=0;
memset(vis,0,sizeof vis);
for (int i=0;i<en;i+=2)
if (!intree[i]&&!vis[i])
{
vis[i]=vis[i^1]=1;
int tmp=dep[fr[i]]-dep[ans[i]]+dep[to[i]]-dep[ans[i]]+1;
if (tmp%2)
{
cov[fr[i]]++;cov[to[i]]++;
cov[ans[i]]-=2;
cnt++;
can[i]=can[i^1]=1;
}
else
{
tag[fr[i]]++;tag[to[i]]++;
tag[ans[i]]-=2;
}
}
for (int i=1;i<=n;++i) if (!dep[i]) dfs2(i),dfs3(i);
// printf("cov :"); for (int i=1;i<=n;++i) printf("%d ",cov[i]); printf("\n");
// printf("tag :"); for (int i=1;i<=n;++i) printf("%d ",tag[i]); printf("\n");
// printf("cnt is %d\n",cnt);
if (!cnt)
{
printf("%d\n",m);
for (int i=1;i<=m;++i) printf("%d%c",i,i==m?'\n':' ');
return 0;
}
else for (int i=0;i<en;i+=2)
{
int a=fr[i],b=to[i];
if (dep[a]>dep[b]) swap(a,b);
if (intree[i]) {if (cov[b]==cnt&&!tag[b]) out[++out[0]]=i/2+1;}
else if (cnt==1&&can[i]) out[++out[0]]=i/2+1;
}
printf("%d\n",out[0]);
for (int i=1;i<=out[0];++i) printf("%d%c",out[i],i==out[0]?'\n':' ');
}