Description
珂朵莉给你一个无向图
其有 个点, 条边
对于每条边,她想知道删了这条边之后这个图是不是一个二分图
Input
第一行两个整数
之后 行,每行两个数 表示有一条 和 之间的无向边
第 个边的序号即为
Output
第一行输出一个整数,表示有多少边满足条件
接下来一行,从小到大输出这些边的序号
如果没有边满足条件,只输出一行一个数 ,注意不要多输出换行
Sample Input
4 4
1 2
1 3
2 4
3 4
Sample Output
4
1 2 3 4
Solution
一个图是二分图当且仅当该图无奇环,若想让该图成为一个二分图,必须破掉所有奇环,那么就要选择所有奇环交集中的一条边,注意到一个奇环和一个偶环在删去一条公共边后依旧是一个奇环,故不能删去偶环上的边
具体做法,首先统计所有自环,如果又有奇环又有自环,显然不行;如果没有奇环但是有超过一个自环也不行;如果没有自环也没有奇环,删去任意一条边都行;如果没有自环只有奇环, 整张图,维护每个点的深度,如果当前点 的一个邻接点 之前被经过,且深度不超过 (如果深度超过 只能是有重边,这种偶环不用管,因为这种边不会出现在奇环的交集中),那么说明 之间构成一个环,且该环是由树上的 这条链和当前的 边构成,我们可以在树上维护一个标记的前缀和,标记 这一段所有的边,表示这些边属于这个环,注意到可以通过 深度差判断该环是奇环还是偶环,如果是奇环则打上正标记,否则打上负标记,假设共有 个奇环,那么被打上 个标记的边都是合法边,同时注意,若只有一个奇环,那么那条非树边也是合法边
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<ctime>
using namespace std;
const int maxn=1000005;
struct node
{
int v,id,next;
}e[2*maxn];
int head[maxn],tot;
void add(int u,int v,int id)
{
e[tot].v=v,e[tot].id=id,e[tot].next=head[u],head[u]=tot++;
}
int n,m,dep[maxn],num[maxn],vis[maxn],cir,self,not_tree;
vector<int>ans;
void dfs(int u,int fa)
{
vis[u]=1;
for(int i=head[u];~i;i=e[i].next)
{
if(i==fa)continue;
int v=e[i].v;
if(!vis[v])
{
dep[v]=dep[u]+1;
dfs(v,i^1);
num[u]+=num[v];
}
else
{
if(dep[v]>dep[u])continue;
if((dep[u]-dep[v]+1)&1)num[u]++,num[v]--,cir++,not_tree=e[i].id;
else num[u]--,num[v]++;
}
}
}
void dfs1(int u,int fa)
{
vis[u]=1;
if(num[u]==cir)ans.push_back(e[fa].id);
for(int i=head[u];~i;i=e[i].next)
if(!vis[e[i].v])dfs1(e[i].v,i);
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
tot=0;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
if(u==v)self++,ans.push_back(i);
else add(u,v,i),add(v,u,i);
}
for(int i=1;i<=n;i++)
if(!vis[i])
{
dep[i]=1;
dfs(i,-1);
}
if(!cir)
{
if(self==0)
{
printf("%d\n",m);
for(int i=1;i<=m;i++)printf("%d%c",i,i==m?'\n':' ');
}
else if(self==1)printf("1\n%d\n",ans[0]);
else printf("0\n");
}
else
{
if(self)printf("0\n");
else
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if(!vis[i])dfs1(i,-1);
if(cir==1)ans.push_back(not_tree);
printf("%d\n",ans.size());
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
}
}
return 0;
}