1. 程式人生 > >CodeForces 789D 歐拉路徑計數,思維

CodeForces 789D 歐拉路徑計數,思維

turn div ble ans nbsp efi ack sta lan

CodeForces 789D

題意:n個點m條邊的無向圖,求經過其中m-2條邊兩次,剩下2條邊一次的方案數有幾種,如果剩下兩條邊的集合一樣算同一種。

tags: 選出兩條邊,其它m-2條邊假想復制成兩條,這樣就是要求歐拉路徑是否存在,即奇點個數是否為0或2。 所以該怎麽選這兩條邊呢?

先把邊分為自環邊和普通邊。

1.選取兩條不相鄰普通邊,圖中存在4個奇點,不滿足歐拉路徑條件;

2.選取兩條相鄰普通邊,圖中存在2個奇點,滿足歐拉路徑條件;

3.選取一條普通邊一條自環,圖中存在2個奇點,滿足歐拉路徑條件;

4.選取兩條自環,圖中存在0個奇點,滿足歐拉路徑條件;

當然如果m條邊覆蓋的集合不是連通的,答案為0。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define
fi first #define se second typedef long long ll; const int N = 2000005; ll n, m, fa[N], ind[N], numa, numb; bool vis[N]; int Find(int x) { return x==fa[x] ? x : (fa[x]=Find(fa[x])); } void Unite(int u, int v) { int fau=Find(u), fav=Find(v); if(fau!=fav) fa[fau]=fav; } int main() { scanf(
"%lld %lld", &n, &m); rep(i,1,n) fa[i]=i; int u, v; rep(i,1,m) { scanf("%d %d", &u, &v); vis[u]=vis[v]=1; if(u!=v) ++ind[v], ++ind[u]; Unite(u, v); if(u!=v) ++numa; else ++numb; } int cnt=0; rep(i,1,n) if(vis[i]==1 && fa[i]==i) ++cnt; if(m==1) printf("0\n"); else if(cnt!=1) printf("0\n"); else { ll ans=0; rep(i,1,n) if(vis[i]==1 && ind[i]>1) ans+= (ind[i]*(ind[i]-1)/2); ans+= (numa*numb); ans+= (numb*(numb-1)/2); printf("%lld\n", ans); } return 0; }

CodeForces 789D 歐拉路徑計數,思維