【思维-搜索-图论】 AtCoder Grand Contest 035——B Even Degrees

前言

改了一晚上,还是WA,无奈之下去问某TAO大佬,结果MAXM乘2就过了!!!

题目

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 700 points

Problem Statement

You are given a simple connected undirected graph with NN vertices and MM edges. The vertices are numbered 11 to NN, and the ii-th edge connects Vertex AiAi and Vertex BiBi. Takahashi will assign one of the two possible directions to each of the edges in the graph to make a directed graph. Determine if it is possible to make a directed graph with an even number of edges going out from every vertex. If the answer is yes, construct one such graph.

Notes

An undirected graph is said to be simple when it contains no self-loops or multiple edges.

Constraints

  • 2≤N≤1052≤N≤105
  • N−1≤M≤105N−1≤M≤105
  • 1≤Ai,Bi≤N(1≤i≤M)1≤Ai,Bi≤N(1≤i≤M)
  • The given graph is simple and connected.

Input

Input is given from Standard Input in the following format:

N M
A1 B1
:
AM BM

Output

If it is impossible to assign directions to satisfy the requirement, print −1−1. Otherwise, print an assignment of directions that satisfies the requirement, in the following format:

C1 D1
:
CM DM

Here each pair (CiCi, DiDi) means that there is an edge directed from Vertex CiCi to Vertex DiDi. The edges may be printed in any order.


Sample Input 1 

4 4
1 2
2 3
3 4
4 1

Sample Output 1

1 2
1 4
3 2
3 4

After this assignment of directions, Vertex 11 and 33 will each have two outgoing edges, and Vertex 22 and 44 will each have zero outgoing edges.


Sample Input 2 

5 5
1 2
2 3
3 4
2 5
4 5

Sample Output 2 

-1

题目大意

给定一个含有n个点m条边的简单无向图,要求将每条边定向,使得每个点的出度都是偶数

分析

(一)首先判无解的情况:m为奇数时无解


(二)接下来构造答案

一种比较简单的构造方法是先随便搜一棵搜索树出来(我用的BFS,记录下每个点被遍历的序号id[ i ])

然后从树的最底层(叶节点)往上处理,由当前节点向上与其“父亲们”确定边的方向,每次都保证当前节点的出度为偶数

怎么保证呢?分两种情况:

1.若当前节点初度为偶数,不用再改变其出度了,就把边练成从父亲到儿子,父亲的出度+1

2.若是奇数,则把这条边连成由儿子到父亲,儿子出度+1,否则由父亲连向儿子,父亲出度+1

用BFS搜出遍历顺序的话,因为BFS是一层一层的,所以当前节点u的父亲id[ fa ]都是小于id[ u ]的,保证了向上处理

(当然这是因为自己实现能力比较弱而自己发明(瞎搞)的,可能会有更优秀的写法qwq...)


(三)该做法的正确性:

由于 m 为偶数,当所有节点满足出度为偶数时,根节点同样满足

其他要点:

1.“ next[  ] ”最好打成“ nxt[  ] ”,避免和有的OJ中的奇奇怪怪的东西重名(因为这个我CE好多次了orz)

2.边的范围MAXM开成点MAXN的两至三倍!

代码

嗯...可能打得会比较清奇...

#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5,MAXM=2e5;
int head[MAXN+5],nxt[MAXM+5],Cnt;
bool vis[MAXN+5],v[MAXN+5];
int cnt[MAXN+5],out[MAXN+5],id[MAXN+5];
int n,m,root;
struct Edge
{
	int u,v;
	Edge(int _u=0,int _v=0){u=_u,v=_v;}
}E[MAXM+5];
struct node
{
	int id,num;
}f[MAXN+5];
bool cmp(node a,node b)
{
	return a.id>b.id;
}
void Addedge(int u,int v)
{
    E[++Cnt]=Edge(u,v);
    nxt[Cnt]=head[u];
    head[u]=Cnt;
}
void BFS(int root)
{
	int tot=0;
	queue<int> que;
	que.push(root);
	vis[root]=1;
	while(!que.empty())
	{
		int u=que.front();que.pop();
		f[++tot].id=tot,f[tot].num=u;
		id[u]=tot;
		for(int i=head[u];i;i=nxt[i])
			if(!vis[E[i].v])
			{
				vis[E[i].v]=1;
				que.push(E[i].v);
			}
	}
}
void Solve()
{
	sort(f+1,f+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		int u=f[i].num;
		for(int j=head[u];j;j=nxt[j])
			if(id[E[j].v]<f[i].id)
			{
				if(out[u]%2)
				{
					out[u]++;
					printf("%d %d\n",u,E[j].v);					
				}
				else
				{
					out[E[j].v]++;
					printf("%d %d\n",E[j].v,u);
				}	
			}
	}
}
int main()
{
	//freopen("degree.in","r",stdin);
	//freopen("degree.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		root=u;
		cnt[u]++,cnt[v]++;
		Addedge(u,v);
		Addedge(v,u); 
	}
	if(m%2)
	{
		printf("-1\n");
		return 0;
	}
	BFS(root);
	Solve();
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值