Codeforces Round #508 (Div. 2) E. Maximum Matching(欧拉路径)

 E. Maximum Matching

题目链接:https://codeforces.com/contest/1038/problem/E

题意:

给出n个项链,每条项链左边和右边都有一种颜色(范围1~4),然后每条项链都有对应的价值。

现在你可以任意改变项链的位置,也可以交换左右两边的颜色,问怎么做才能得到最大的价值。一条项链得到价值,就要求其左边的颜色和左边的项链右边颜色相等,并且右边的颜色和右边项链左边的颜色相等。

 

题解:

分析就可以发现这个题就是找一条权值最大的欧拉路径(每条边刚好经过一次),我们这样构造,将两边的颜色看作点,然后价值看作边上的权值并且连接这两个点。

由于存在欧拉路径的充要条件就是度数为奇数的点不超过两个,这个题目中最多只有四个点,所以我们只需要枚举去掉一条边然后来跑欧拉路径就是了。

具体细节见代码吧:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 105;
int n, sum;
int d[N], vis[N], del[N],check[N];
struct node {
    int id, v, val;
};
vector <node> g[N], edges[N];
void Euler(int u, int fa) {
    check[u]=1;
    for(auto v : g[u]) {
        if(del[v.id] || vis[v.id])
            continue ;
        vis[v.id]=1;
        sum += v.val;
        Euler(v.v, u);
    }
}
bool Can() {
    int cnt = 0;
    for(int i = 1; i <= 4; i++) {
        if(check[i] && (d[i] & 1))
            cnt++;
    }
    return cnt <= 2;
}
void init(){
    memset(vis, 0, sizeof(vis));
    memset(check,0,sizeof(check));
    sum = 0;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i++) {
        int c1, c2, v;
        cin >> c1 >> v >> c2;
        g[c1].push_back(node{i, c2, v});
        g[c2].push_back(node{i, c1, v});
        d[c1]++;
        d[c2]++;
        edges[i].push_back(node{c1, c2, v});
    }
    int ans = 0;
    for(int i = 1; i <= 4; i++) {
        init();
        Euler(i, -1);
        if(Can())
            ans = max(ans, sum);
    }
    for(int i = 1; i <= n; i++) {
        del[i - 1] = 0;
        del[i] = 1;
        d[edges[i][0].id]--;
        d[edges[i][0].v]--;
        for(int j = 1; j <= 4; j++) {
            init();
            Euler(j, -1);
            if(Can()){
                ans = max(ans, sum);
            }
        }
        d[edges[i][0].id]++;
        d[edges[i][0].v]++;
    }
    cout << ans;
    return 0;
}

 

posted @ 2019-03-17 21:59  heyuhhh  阅读(177)  评论(0编辑  收藏  举报