1. 程式人生 > >【尤拉路】Codeforces Round #508 (Div. 2) E. Maximum Matching

【尤拉路】Codeforces Round #508 (Div. 2) E. Maximum Matching

Step1 Problem:

給你 n 個塊,每個塊左右兩邊有顏色,中間是塊的權值,如果不同的塊的邊顏色一樣,那麼它們可以合併成新的一塊。
例:兩個塊分別是 c1 v1 c2, c2 v2 c1,那麼這兩個塊可以變成 c1 v1+v2 c1,或者 c2 v1+v2 c2。
你可以選擇 n 塊的任意塊,求合成後的權值最大值。
資料範圍:
1<=n<=100, 1 <= c <= 4, 1 <= v <= 100000.

Step2 Ideas:

尤拉路徑:如果圖 G 中的一個路徑包括每個邊恰好一次,則該路徑稱為尤拉路徑。
歐拉回路:

如果一個迴路是尤拉路徑,則稱為歐拉回路。
一個圖奇點個數一定是偶數個
如果一個無向圖是連通的,且最多隻有兩個奇點,則一定存在尤拉道路。

因為本題最多隻有四個點,當連通塊個數是 1 的時候 同時 四個點都是奇點,當前不是尤拉路。
否則都是尤拉路,如果是尤拉路代表能一筆走完,就代表可以把該連通塊所有塊都連一起,權值就是所有塊的和。
核心點:如果不是尤拉路的話,代表不能一筆走完,我們就得去除某條邊,對於當前圖找最大權值的尤拉路。

Step3 Code:

#include<bits/stdc++.h>
using namespace std;
const
int inf = 0x3f3f3f3f; struct node { int to, w, rev, flag;//目的,權值,反向邊,標記該邊是否存在 }; int vis[10], d[10], c; int bs[10]; vector<node> Map[5]; void dfs(int u) { vis[u] = c; for(int i = 0; i < Map[u].size(); i++) { int to = Map[u][i].to, flag = Map[u][i].flag; if(flag == 1) continue
; if(!vis[to]) dfs(to); } } int solve() { c = 0; int cnt = 0, odd = 0; int ans = 0; memset(vis, 0, sizeof(vis)); for(int i = 1; i <= 4; i++) { if(!vis[i]) { c++; dfs(i), cnt++; int sum = 0; for(int j = 1; j <= 4; j++) { if(vis[j] == c) { if(d[j]&1) odd++; sum += bs[j]; } } ans = max(ans, sum); } } if(cnt == 1 && odd == 4) return 0;//不是尤拉路 else return ans;//該圖存在尤拉路,返回權值最大的尤拉路 } int main() { int n, u, v, w; scanf("%d", &n); memset(d, 0, sizeof(d));//記錄每個點的度 memset(bs, 0, sizeof(bs));//記錄到 v 的權值和 for(int i = 1; i <= n; i++) { scanf("%d %d %d", &u, &w, &v); d[u]++, d[v]++; bs[v] += w; Map[u].push_back((node){v, w, Map[v].size(), 0}); Map[v].push_back((node){u, w, Map[u].size()-1, 0}); } int ans = 0; ans = solve(); if(ans) { printf("%d\n", ans); return 0; } //刪除邊,找權值最大的尤拉路 for(int i = 1; i <= 4; i++) { for(int j = 0; j < Map[i].size(); j++) { int to = Map[i][j].to, w = Map[i][j].w, &flag = Map[i][j].flag; if(to == i) continue; flag = 1;//刪邊 Map[to][Map[i][j].rev].flag = 1; d[i]--, d[to]--;//減度 ans = max(ans, solve()-w);//更新最大值 Map[to][Map[i][j].rev].flag = 0;//恢復邊 flag = 0; d[i]++, d[to]++; } } printf("%d\n", ans); return 0; }