传送门:http://codeforces.com/contest/788/problem/B
好题!好题!
首先图不连通的时候肯定答案是0,我们下面讨论图联通的情况
首先考虑,如果我们每条边都经过两边,那么肯定是可行的
因为这样相当于把每条边复制一遍,然后问图中是否存在欧拉路径
既然每条边都出现了两遍,那么所有点的度数一定都是偶数,所以肯定有欧拉路径
现在考虑将某两条边变成出现一遍,这样的话可能会有一些点的度数变成奇数
如果我们把两条非自环的边变成出现一遍,并且这两条边不交于同一个点,那么就会有四个度数为奇数的点,则图中不存在欧拉路径
如果我们把两条非自环的边变成出现一遍,并且这两条边交于同一个点,那么就会有两个度数为奇数的点,存在欧拉路径
如果我们把两条自环边变成出现一遍,所有点的度数仍然为偶数,存在欧拉路径
如果我们把一条自环,一条非自环的边变成出现一遍,那么就会有两个度数为奇数的点,存在欧拉路径
所以一共就几种情况,除去判联通的部分,我们只要记录每个点的度数(不含自环)和自环的数量就好了
因为题目中保证一条边不会出现两遍,所以我们的方法才是可行的
代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 const int MAXN = 1000010; 6 7 int n, m; 8 9 namespace Graph { 10 int head[MAXN], nxt[MAXN<<1], to[MAXN<<1], eidx; 11 void init() { 12 eidx = 0; 13 memset( head, -1, sizeof(head) ); 14 } 15 void adde( int u, int v ) { 16 to[eidx] = v, nxt[eidx] = head[u], head[u] = eidx++; 17 } 18 } 19 20 bool ing[MAXN] = {0}, vis[MAXN] = {0}; // ing表示这个点是否存在于图中,因为题目只要求边互相联通,所以对于没有度数的点可以看做不存在 21 queue<int> q; 22 bool bfs() { // bfs判联通 23 using namespace Graph; 24 for( int i = 1; i <= n; ++i ) 25 if( ing[i] ) { 26 q.push(i), vis[i] = true; 27 break; 28 } 29 while( !q.empty() ) { 30 int u = q.front(); q.pop(); 31 for( int i = head[u]; ~i; i = nxt[i] ) { 32 int v = to[i]; 33 if( vis[v] ) continue; 34 q.push(v), vis[v] = true; 35 } 36 } 37 for( int i = 1; i <= n; ++i ) 38 if( ing[i] && !vis[i] ) 39 return false; 40 return true; 41 } 42 43 int deg[MAXN] = {0}, loop = 0; // 每个点的度数(不含自环)和总的自环数量 44 int main() { 45 scanf( "%d%d", &n, &m ); 46 Graph::init(); 47 for( int i = 0; i < m; ++i ) { 48 int u, v; scanf( "%d%d", &u, &v ); 49 ing[u] = ing[v] = true; 50 if( u != v ) { 51 Graph::adde(u,v), ++deg[u]; 52 Graph::adde(v,u), ++deg[v]; 53 } else { // 自环 54 Graph::adde(u,v), ++loop; 55 } 56 } 57 if( !bfs() || m < 2 ) { 58 puts("0"); 59 return 0; 60 } 61 ll ans = (ll)loop*(m-loop) + (ll)loop*(loop-1)/2; // 选一个自环和一个非自环,或者选两个自环 62 for( int i = 1; i <= n; ++i ) 63 ans += (ll)deg[i]*(deg[i] - 1)/2; // 选两个非自环,且交于同一点的边 64 cout << ans << endl; 65 return 0; 66 }