您的位置:首页 > 运维架构

2015多校.MZL's endless loop(欧拉回路的机智应用 || 构造)

2015-08-05 10:30 225 查看

MZL's endless loop

Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 898 Accepted Submission(s): 178
Special Judge


[align=left]Problem Description[/align]
As we all kown, MZL hates the endless loop deeply, and he commands you to solve this problem to end the loop.
You are given an undirected graph with n vertexs and m edges. Please direct all the edges so that for every vertex in the graph the inequation |out degree − in degree|≤1 is satisified.
The graph you are given maybe contains self loops or multiple edges.

[align=left]Input[/align]
The first line of the input is a single integer T, indicating the number of testcases.
For each test case, the first line contains two integers n and m.
And the next m lines, each line contains two integers ui and vi, which describe an edge of the graph.
T≤100, 1≤n≤105, 1≤m≤3∗105, ∑n≤2∗105, ∑m≤7∗105.

[align=left]Output[/align]
For each test case, if there is no solution, print a single line with −1, otherwise output m lines,.
In ith line contains a integer 1 or 0, 1 for direct the ith edge to ui→vi, 0 for ui←vi.

[align=left]Sample Input[/align]

2
3 3
1 2
2 3
3 1
7 6
1 2
1 3
1 4
1 5
1 6
1 7

[align=left]Sample Output[/align]

1
1
1
0
1
0
1
0
1

#include<vector>
#include<string.h>
#include<stdio.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int M = 3e5 + 10 ;
struct Edge {
int v ;
bool vis ;
int nxt ;
Edge () {}
Edge (int v , int vis , int nxt) :
v(v) , vis(vis) , nxt(nxt) {}
}e[M << 2] ;
int H[M] , E ;

int n , m ;
int in[M] ;
int res[M << 1] ;
void addedge (int u , int v) {
e[E] = Edge (v , 0 , H[u]) ;
H[u] = E ++ ;
e[E] = Edge (u , 0 , H[v]) ;
H[v] = E ++ ;
}

void dfs (int u) {
for (int &i = H[u] ; ~i ; ) {
int v = e[i].v ;
if (e[i].vis) {
i = e[i].nxt ;
continue ;
}
e[i].vis = 1 ;
e[i^1].vis = 1 ;
res[i >> 1] = i & 1 ;
in[v] -- ;
in[u] -- ;
i = e[i].nxt ;
dfs (v) ;
}
}

void mend () {
int p = -1 ;
for (int i = 1 ; i <= n ; i ++) {
if (in[i] & 1) {
if (p == -1) {
p = i ;
}
else {
addedge (p , i) ;
in[p] ++ ;
in[i] ++ ;
p = -1;
}
}
}
}

void solve () {
mend () ;
for (int i = 1 ; i <= n ; i ++) {
if(in[i]) {
dfs (i) ;
}
}
for (int i = 0 ; i < m ; i ++) printf ("%d\n" , res[i]) ;
}

int main () {
int T ;
scanf ("%d" , &T ) ;
while (T --) {
scanf ("%d%d" , &n , &m) ;
for (int i = 0 ; i <= n ; i ++) H[i] = -1 ;
E = 0 ;
for (int i = 0 ; i < m ; i ++) {
int u , v ;
scanf ("%d%d" , &u , &v) ;
addedge (u , v) ;
in[u] ++ ;
in[v] ++ ;
}
solve () ;
}
return 0 ;
}


View Code
根据“欧拉回路”的定义,当连通图所有点的度数为偶数时,那么必然会存在一条路线,使得经过所有点并且每条边只经过一次

[align=left]所以很明显如果我们能在构造是利用好这个性质的话,整个复杂度为O(m + k)[/align]
[align=left]为什么还有一个常数k?你很容易回发现,题目给定的边数不一定回使每个点的度数为 偶数 , 那么怎么办呢?补边咯,把两两为奇数度的点之间加一条边即可。[/align]
[align=left]那么你可定又会有疑问了,这样添加边会不会导致最后的 “题设的条件” 收到影响?[/align]
[align=left]没事的,因为题目说了 |入度 - 出度| <= 1 ,因为你构造的是欧拉回路,所以找到后的欧拉回路肯定满足所有点|入度 - 出度| = 0 , 而我们在每个点上最多只加了[/align]
[align=left]一条边,所以去掉后,肯定 <= 1 的。[/align]
[align=left] [/align]
[align=left]铭神说,构造回路时,因为每个点可能会被遍历到多次,这样如果姿势不对,很容易导致又把那个点的所有边遍历一遍,导致复杂度又变成O(n*m),所以去仔细[/align]
[align=left]看代码吧233[/align]

(欧拉通路:除了两个点外度数为奇数,其他点的度数为偶数)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: