Codeforces - 1038E - Maximum Matching(欧拉回路 + 建图)

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

8.1 题意

n ( 1 ≤ n ≤ 100 ) n(1 \le n \le 100) n(1n100) 个条带,每个条带的格式为 [color1|value|color2] \texttt{[color1|value|color2]} [color1|value|color2]( 1 ≤ color ≤ 4 , 1 ≤ value ≤ 1 0 5 1 \le \text{color} \le 4,1 \le \text{value} \le 10^5 1color4,1value105),两个条带可以连接当且仅当它们有一个公共端。

问权值之和最大的连通条带。

8.2 解题过程

建立一个 4 4 4 个结点的图,对于每一个条带来说,颜色向颜色建边。

则我们会发现,欧拉通路不存在的情况只有一种:只有一个连通块,且奇度顶点的个数为 4 4 4

其他情况下,答案就是每个连通块权值(等价于欧拉通路的权值和)的最大值。

在欧拉通路不存在时,只需删掉任意一条非自环的边,即可回到上面的合法情况。

因此,在欧拉通路不存在时,枚举要删的边,然后按照合法情况进行求解,最后取最大答案即可。

时间复杂度: O ( n 2 ) O(n^2) O(n2)

8.3 错误点

真的很嫌弃自己,写个这么简单的程序能写出一堆 bug \texttt{bug} bug 来,还 WA 了好多发。

  1. 枚举要删的边时,一定要跳过自环,因为自环删掉之后奇度顶点数量不变。
  2. 删边时不要忘记更新两个顶点的度。

8.4 代码

int n, m;
int head[maxn], cnt;
int col[maxn], deg[maxn], cntt[maxn], sum[maxn];
bool mark[2 * maxn];
struct edge
{
    int v, nxt, w;
} Edge[2 * maxn];
void init()
{
    memset(head, -1, sizeof(head));
    cnt = 0;
}
void reset() {
    memset(col, 0, sizeof(col));
    memset(sum, 0, sizeof(sum));
    memset(cntt, 0, sizeof(cntt));
}
void addedge(int u, int v, int w)
{
    Edge[cnt].v = v;
    Edge[cnt].w = w;
    Edge[cnt].nxt = head[u];
    head[u] = cnt++;
}
void dfs(int id, int color) {
    col[id] = color;
    for (int i = head[id]; i != -1; i = Edge[i].nxt) {
        int v = Edge[i].v;
        if (!col[v] && !mark[i]) dfs(v, color);
    }
}
int solve() {
    reset();
    int num = 0;
    for (int i = 1; i <= 4; i++) {
        if (!col[i]) dfs(i, ++num);
    }
    for (int i = 1; i <= 4; i++) {
        if (deg[i] & 1) cntt[col[i]]++;
    }
    for (int i = 0; i < cnt; i += 2) {
        if (mark[i]) continue;
        int u = Edge[i ^ 1].v;
        int v = Edge[i].v;
        int w = Edge[i].w;
        sum[col[u]] += w;
    }
    int res = 0;
    for (int i = 1; i <= num; i++) {
        res = max(res, sum[i]);
    }
    return res;
}
int main()
{
    scanf("%d", &n);
    init();
    for (int i = 1; i <= n; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &w, &v);
        addedge(u, v, w);
        addedge(v, u, w);
        deg[u]++, deg[v]++;
    }
    int ans = solve();
    bool isok = true;
    for (int i = 1; i <= 4; i++) {
        if (cntt[i] > 2) {
            isok = false;
            break;
        }
    }
    if (isok) return 0 * printf("%d\n", ans);
    ans = 0;
    for (int i = 0; i < cnt; i += 2) {
        int u = Edge[i ^ 1].v;
        int v = Edge[i].v;
        if (u == v) continue;
        deg[u]--, deg[v]--;
        mark[i] = mark[i ^ 1] = true;
        ans = max(ans, solve());
        mark[i] = mark[i ^ 1] = false;
        deg[u]++, deg[v]++;
    }
    printf("%d\n", ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值