【歐拉回路+最小生成樹】SD開車@山東2018省隊一輪集訓day1
目錄
【歐拉回路+最小生成樹】SD開車@山東2018省隊一輪集訓day1
PROBLEM
題目描述
作為欽欽草原最綠的男人,楊某針每天都要開車巡視欽欽草原一圈。
欽欽草原由 n 個城市組成,m 條雙向道路連線著它們。經過第 i 條道路要花費的時間是\(2^i\)。
楊某針想要經過每條道路至少一次,在此基礎上他想最小化他花費的時間。但作為 曾經 CTSC 的 Cu 選手,他並不能很快地計算出這個問題。所以他向你求助。
輸入
輸入第一行包含兩個正整數n,m。
接下來m行,每行兩個正整數\(a_i\),\(b_i\),表示第i條邊連線點\(a_i\)和\(b_i\),它的權值為\(2^i\)。保證\(a_i\neq b_i\),不存在重邊,且任意兩個點之間可以互相到達。
輸出
輸出一行一個整數,表示答案對\(10^9\)+7取模的值。
樣例輸入
4 5
1 2
3 4
2 3
1 3
2 4
樣例輸出
70
提示
最優的路線應當為 1-2-3-4-2-3-1。
對於20%的資料,n,m≤20。
對於40%的資料,n,m≤2,000。
對於100%的資料,n≤400,000,m≤500,000。
SOLUTION
若存在一條從節點S出發的路徑,恰好不重不漏地經過每條邊一次(可以重複經過圖中的節點),最終回到起點S,則稱該路徑為歐拉回路
。存在歐拉回路的無向圖被稱為尤拉圖。
要經過每條道路至少一次,可以對比在歐拉回路中,每條邊恰好經過一次。若最佳路線經過某一條邊n+1次,可以看作在原圖中加上了n次那條邊。由原圖G加上重複走的邊得到G',G'一定是一個尤拉圖,由尤拉圖的性質,G'中每個點的度一定為偶數。
題目要求最小花費,也就是要加的邊的權值和最小。若我分若干次去新增邊,這裡可以貪心假設,每次加的一個邊集一定是某兩個度為奇數的點的最短路徑上的邊,然後使得這兩個點的度變為偶數。
而至於如何去求兩個奇數度點的最短路,可以從邊的權值上下手——第i條邊的權值是\(2^i\)。用求最小生成樹的Kruskal演算法,我們從按編號(也就是權值)小到大列舉邊,然後並查集維護,建出一棵最小生成樹。因為\(2^n = 2^{n-1} + 2^{n-2} + ... + 2^1+ 2\)
最後dfs遍歷生成樹,回溯時判斷當前點的度數是否為奇數,如果是奇數,讓答案再加上該點和它的父節點所連的邊的權值,並更新兩點的度數。
最終答案要加上原圖中所有邊的權值和。
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 4e5 + 5;
const int MAXE = 5e5+5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9+7;
int degree[MAXN];
int u[MAXE],v[MAXE];
struct edge{
int u,v,w,nex;
}ed[MAXN<<1];
int head[MAXN],tot;
void addedge(int uu,int vv,int w){
tot++;
ed[tot].u = uu;
ed[tot].v = vv;
ed[tot].w = w;
ed[tot].nex = head[uu];
head[uu] = tot;
}
int fa[MAXN];
int DjsGet(int x){
if(x==fa[x])return x;
return fa[x] = DjsGet(fa[x]);
}
ll fastpow(ll a,ll n){
ll res = 1;
while(n){
if(n&1)res=res*a%MOD;
a = a*a%MOD;
n>>=1;
}
return res;
}
ll ans;
void dfs(int u,int p){
for(int i=head[u];i;i = ed[i].nex){
int v = ed[i].v;
if(i!=(p^1))
dfs(v,i);
}
if(degree[u]&1){
ans=(ans+fastpow(2,ed[p].w))%MOD;
degree[u]++;
degree[ed[p].u]++;
}
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&u[i],&v[i]);
degree[u[i]]++;
degree[v[i]]++;
}
tot++;
for(int i = 1;i<=n;i++)fa[i] = i;
for(int i=1;i<=m;i++){
int fx = DjsGet(u[i]),fy = DjsGet(v[i]);
if(fx!=fy){
fa[fx] = fy;
addedge(u[i],v[i],i);
addedge(v[i],u[i],i);
}
ans=(ans+fastpow(2,i))%MOD;
}
dfs(ed[2].u,0);
printf("%lld\n",ans);
return 0;
}