[CF788B]Weird journey_欧拉回路

Weird journey

题目链接http://codeforces.com/contest/788/problem/B

数据范围:略。


题解

我们发现就是要求,把每条无向边拆成两条无向边,其中有两条拆成一条,问这个图有没有欧拉回路。

无向图欧拉回路的充要条件是度数为奇数的点数等于$0$或者$2$。

那么我们的删边方式就分成了三种:

第一种,删任意两个自环。

第二种,删一个自环和任意一条边。

第三种,删两条有公共端点的边,

随便枚举一下就行。

代码

#include <bits/stdc++.h>

#define N 1000010 

using namespace std;

typedef long long ll;

char *p1, *p2, buf[100000];

#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )

int rd() {
	int x = 0, f = 1;
	char c = nc();
	while (c < 48) {
		if (c == '-')
			f = -1;
		c = nc();
	}
	while (c > 47) {
		x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
	}
	return x * f;
}

int n, m, t;

ll d[N];

int zh[N];

bool vis[N];

int tot, head[N], nxt[N << 1], to[N << 1];

inline void add(int x, int y) {
	to[ ++ tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
}

void dfs(int p) {
	vis[p] = true;
	for (int i = head[p]; i; i = nxt[i]) {
		if (!vis[to[i]]) {
			dfs(to[i]);
		}
    }
}

int main() {
	n = rd(), m = rd();
	for (int i = 1; i <= m; i ++ ) {
		int x = rd(), y = rd();
		add(x, y), add(y, x);
		if (x == y) {
			t ++ , zh[x] ++ ;
            continue; 
        }
		d[x] ++ , d[y] ++ ;
    }
	for (int i = 1; i <= n; i ++ ) {
        if (d[i]) {
            dfs(i);
            break;
        }
	}
	for (int i = 1; i <= n; i ++ ) {
		if (!vis[i]) {
            if (d[i] || zh[i]) {
				puts("0");
                return 0;
            }
        }
	}
	ll ans = 0;
    ans += (ll)t * (t - 1) / 2;
    ans += (ll)t * (m - t);
    for (int i = 1; i <= n; i ++ ) {
        if (d[i] >= 2) {
			ans += (ll)d[i] * (d[i] - 1) / 2;
		}
	}
	cout << ans << endl ;
	return 0;
}
posted @ 2019-10-29 20:37  JZYshuraK_彧  阅读(128)  评论(0编辑  收藏  举报