CodeForces - 19E Fairy(图论 + DP)

185 篇文章 0 订阅
116 篇文章 0 订阅

Description

Once upon a time there lived a good fairy A. One day a fine young man B came to her and asked to predict his future. The fairy looked into her magic ball and said that soon the fine young man will meet the most beautiful princess ever and will marry her. Then she drew on a sheet of paper n points and joined some of them with segments, each of the segments starts in some point and ends in some other point. Having drawn that picture, she asked the young man to erase one of the segments from the sheet. Then she tries to colour each point red or blue so, that there is no segment having points of the same colour as its ends. If she manages to do so, the prediction will come true. B wants to meet the most beautiful princess, that's why he asks you to help him. Find all the segments that will help him to meet the princess.

Input

The first input line contains two integer numbers: n — amount of the drawn points and m — amount of the drawn segments (1 ≤ n ≤ 104, 0 ≤ m ≤ 104). The following m lines contain the descriptions of the segments. Each description contains two different space-separated integer numbers vu (1 ≤ v ≤ n, 1 ≤ u ≤ n) — indexes of the points, joined by this segment. No segment is met in the description twice.

Output

In the first line output number k — amount of the segments in the answer. In the second line output k space-separated numbers — indexes of these segments in ascending order. Each index should be output only once. Segments are numbered from 1 in the input order.

Sample Input

Input
4 4
1 2
1 3
2 4
3 4
Output
4
1 2 3 4 
Input
4 5
1 2
2 3
3 4
4 1
1 3
Output
1
5 

Source

Codeforces Beta Round #19

题意:给一个无向图,现在让你删一条边,使得删后的图为二分图,要求输出所有删边方案。

分析:一个无向图为二分图的充要条件是图中无奇环。我们可以对原图做一遍dfs,这样可以将图中的所有环分解为一个个“基环”,基环只有一个连向祖先的边,且图中所有的环都可以由几个基环的边异或得到,因为要求删一条边后图中不存在基环,所以这条边至少要存在于所有的奇数基环中,然后考虑它是不是也存在于所有的奇环中,这时我们可以注意到如果这条边同时被一个偶数基环覆盖,那么无论删不删这条边都会存在一个复合的奇环,这样我们就得到了一个必要条件,然后我们证明这个条件也是充分条件:如果我们删掉这条边,那么便破坏了图中所有的奇基环,此时图中仅存在偶基环,又因为所有的复合奇环至少有一个奇基环参与,且我们删的这条边同时也存在于复合后的大环中(因为没有偶基环覆盖它),所以此时图中也一定 无复合奇环。

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<ctime>  
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define N 10005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
vector <pii> G[N];
int n,m,u,v,tot_ans,tot_odd,edge_first,jud[N],vis[N],f_odd[N],f_even[N],dep[N];
pii edge[N];
void dfs(int u,int fa,int edg)
{
	if(fa > 0) dep[u] = dep[fa] + 1;
	vis[u] = true;
	for(int i = 0;i < G[u].size();i++)
	{
		int v = G[u][i].first,e = G[u][i].second;
		if(v != fa)
		 if(vis[v])
		 {
		 	 if(dep[v] > dep[u]) continue;                            //防止反向边重复 
		 	 if((dep[u] - dep[v]) & 1)
			 {
			   	  f_even[u]++;
			   	  f_even[v]--;
			 }
			 else
			 {
			 	  tot_odd++;
			 	  edge_first = e;
			 	  f_odd[u]++;
			 	  f_odd[v]--;
			 }	
		 }
		 else 
		 {
		 	  dfs(v,u,e);
			  f_even[u] += f_even[v];
			  f_odd[u] += f_odd[v];	
		 } 
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= m;i++)
	{
		scanf("%d%d",&u,&v);
		G[u].push_back(make_pair(v,i));
		G[v].push_back(make_pair(u,i));
		edge[i] = make_pair(u,v); 
	}
	for(int i = 1;i <= n;i++)
	 if(!vis[i]) dfs(i,-1,-1);
	if(!tot_odd) 
	{
		printf("%d\n",m);
		for(int i = 1;i <= m;i++) printf("%d ",i);
		return 0;
	}
	for(int i = 1;i <= m;i++)
	{
		int u = edge[i].first,v = edge[i].second;
		if(dep[u] > dep[v]) swap(u,v);
		if(i == edge_first && tot_odd == 1)
		{
			tot_ans++; 
			jud[i] = true; 
		}
		if(dep[v] - dep[u] != 1) continue;
		if(!f_even[v] && f_odd[v] == tot_odd)
		{
			tot_ans++;
			jud[i] = true;
		}
	}
	printf("%d\n",tot_ans);
	for(int i = 1;i <= m;i++)
	 if(jud[i]) printf("%d ",i);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值