HDU 4687 Boke and Tsukkomi (一般图最大匹配 技巧)

版权声明:get busy living...or get busy dying https://blog.csdn.net/qq_41444888/article/details/89266669

 https://vjudge.net/problem/HDU-4687

又是被自己蠢哭的一天,debug了一个多小时,原来是把一个bool数组开成了int类型的,然后memcpy了两个不同类型的数组,,,蠢爆了,还有玄学PE,大半夜的心态崩了

这道题为啥不是二分图呢,纳闷了好久,后来发现原来可以形成1-2 2-3 3-1这样的奇圈,所以不可以用二分图解(二分图均为偶圈),这让我严重怀疑以前做二分图的题的时候思考的正确性。。。还有一个技巧就是把每条边强制配对,这样可以判断去掉这条边对最终结果是否有影响,如果只是去边而不去点的话结果是不对的

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 50;
int n; // 顶点个数,从1 - N
bool g[maxn][maxn];
int match[maxn]; // 存每个点的匹配信息
bool inq[maxn], inp[maxn], inb[maxn];
int head, tail;
int q[maxn];
int start, finish;
int nbase;
int f[maxn], base[maxn];
int Count;//匹配数,匹配对数是Count/2
void push(int u)
{
    q[tail] = u;
    tail ++;
    inq[u] = 1;
}
int pop()
{
    int res = q[head];
    head ++;
    return res;
}
int fc(int u, int v)//FindCommonAncestor寻找公共祖先
{
    memset(inp, 0, sizeof(inp));
    while(1)
    {
        u = base[u];
        inp[u] = 1;
        if(u == start) break;
        u = f[match[u]];
    }
    while(1)
    {
        v = base[v];
        if(inp[v]) break;
        v = f[match[v]];
    }
    return v;
}
void rt(int u)//ResetTrace重置标记
{
    int v;
    while(base[u] != nbase)
    {
        v = match[u];
        inb[base[u]] = inb[base[v]] = 1;
        u = f[v];
        if(base[u] != nbase) f[u] = v;
    }
}
void bc(int u, int v)//BloosomContract 花 传播
{
    nbase = fc(u, v);
    memset(inb , 0, sizeof(inb));
    rt(u);
    rt(v);
    if(base[u] != nbase) f[u] = v;
    if(base[v] != nbase) f[v] = u;
    for(int tu = 1; tu <= n; tu ++)
    {
        if(inb[base[tu]])
        {
            base[tu] = nbase;
            if(! inq[tu])
                push(tu);
        }
    }
}
void fa()// FindAugmentingPath 寻找增广路
{
    memset(inq, 0, sizeof(inq));
    memset(f, 0, sizeof(f));
    for(int i = 1; i <= n; i ++)
        base[i] = i;
    head = tail = 1;
    push(start);
    finish = 0;
    while(head < tail)
    {
        int u = pop();
        for(int v = 1; v <= n; v ++)
        {
            if(g[u][v] && (base[u] != base[v]) && (match[u] != v))
            {
                if((v == start) || ((match[v] > 0) && f[match[v]] > 0))
                    bc(u, v);
                else if(f[v] == 0)
                {
                    f[v] = u;
                    if(match[v] > 0)
                        push(match[v]);
                    else
                    {
                        finish = v;
                        return ;
                    }
                }
            }
        }
    }
}
void ap() // AugmentPath 增广路
{
    int u, v, w;
    u = finish;
    while(u > 0)
    {
        v = f[u];
        w = match[v];
        match[v] = u;
        match[u] = v;
        u = w;
    }
}
void ed() // Edmonds 进行匹配
{
    memset(match, 0, sizeof(match));
    for(int u = 1; u <= n; u ++)
    {
        if(match[u] == 0)
        {
            start = u;
            fa();
            if(finish > 0) ap();
        }
    }
}
bool G[maxn][maxn];
int main()
{
    int m;
    while(scanf("%d%d", &n, &m) != EOF)
    {
        memset(g, 0, sizeof(g));
        pair<int, int> p[150];
        int u, v;
        for(int i = 1; i <= m; i ++)
        {
            scanf("%d%d", &u, &v);
            g[u][v] = g[v][u] = 1;
            p[i] = make_pair(u, v);
        }
        ed(); // 进行匹配
        Count = 0;
        for(int u = 1; u <= n; u ++)
            if(match[u] > 0)
                Count ++;

        memcpy(G, g, sizeof(g));
        vector<int> V;
        int ans = Count / 2 - 1;
        for(int j = 1; j <= m; j ++)
        {
            memcpy(g, G, sizeof(G));
            int x = p[j].first, y = p[j].second;
            for(int i = 1; i <= n; i ++)
                g[i][x] = g[x][i] = g[y][i] = g[i][y] = 0;
            ed();
            Count = 0;
            for(int u = 1; u <= n; u ++)
            {
                if(match[u] > 0)
                    Count ++;
            }
            if((Count / 2) < ans) V.push_back(j);
        }
        int sz = V.size();
        printf("%d\n", sz);
        for(int i = 0; i < sz; i ++)
            if(i != sz - 1)
                printf("%d ", V[i]);
            else printf("%d", V[i]);
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41444888/article/details/89266669