一般图匹配带花树hdu4687 & ural 1099

S - Boke and Tsukkomi HDU - 4687 

A new season of Touhou M-1 Grand Prix is approaching. Girls in Gensokyo cannot wait for participating it. Before the registration, they have to decide which combination they are going to compete as. Every girl in Gensokyo is both a boke (funny girl) and a tsukkomi (straight girl). Every candidate combination is made up of two girls, a boke and a tsukkomi. A girl may belong to zero or more candidate combinations, but one can only register as a member of one formal combination. The host of Touhou M-1 Grand Prix hopes that as many formal combinations as possible can participate in this year. Under these constraints, some candidate combinations are actually redundant as it\'s impossible to register it as a formal one as long as the number of formal combinations has to be maximized. So they want to figure out these redundant combinations and stop considering about them. 

Input

There are multiple test cases. Process to the End of File. 
The first line of each test case contains two integers: 1 ≤ N ≤ 40 and 1 ≤ M ≤123, where N is the number of girls in Gensokyo, and M is the number of candidate combinations. The following M lines are M candidate combinations, one by each line. Each combination is represented by two integers, the index of the boke girl 1 ≤ Bi ≤ N and the index of the tsukkomi girl 1 ≤ T i ≤ N, where B i != T i.

Output

For each test case, output the number of redundant combinations in the first line. Then output the space-separated indexes of the redundant combinations in ascending order in the second line.

Sample Input

4 4
1 3
2 3
2 4
3 1
6 6
1 2
3 2
3 4
5 2
5 4
5 6

Sample Output

1
2
3
2 4 5

我们可以先求出哪些边是可能存在于最大匹配中的,然后剩下的边就是绝对不可能在最大匹配中了

求哪些边可能存在于最大匹配中,超简单,只需要强制将那条边上的两个点匹配(即删除),然后求最大匹配,如果是tot-1,那么这条边就可以存在于最大匹配中

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 50;
deque<int> Q;
//g[i][j]存放关系图:i,j是否有边,match[i]存放i所匹配的点
bool g[maxn][maxn],inque[maxn],inblossom[maxn],vis[150];
int match[maxn],pre[maxn],base[maxn];
int n,m,mmg;
vector<int>res;
struct node
{
    int u,v;
}com[150];

//找公共祖先
int lca(int u,int v)
{
    bool inpath[maxn]={0};
    while(1)
    {
        u = base[u];
        inpath[u] = 1;
        if(match[u] == -1)break;
        u = pre[match[u]];
    }
    while(1)
    {
        v = base[v];
        if(inpath[v])return v;
        v = pre[match[v]];
    }
}

//压缩花
void reset(int u,int anc)
{
    while(u != anc)
    {
        int v = match[u];
        inblossom[base[u]] = 1;
        inblossom[base[v]] = 1;
        v = pre[v];
        if(base[v] != anc) pre[v] = match[u];
        u = v;
    }
}

void contract(int u,int v,int n)
{
    int anc = lca(u,v);
    memset(inblossom,0,sizeof(inblossom));
    reset(u,anc);reset(v,anc);
    if(base[u] != anc)pre[u] = v;
    if(base[v] != anc)pre[v] = u;
    for(int i = 1;i <= n;i++)
        if(inblossom[base[i]])
        {
            base[i] = anc;
            if(!inque[i])
            {
                Q.push_back(i);
                inque[i] = 1;
            }
        }
}

bool dfs(int S,int n)
{
    for(int i = 0;i <= n;i++)
        pre[i] = -1,inque[i] = 0,base[i] = i;
    Q.clear();Q.push_back(S);inque[S] = 1;
    while(!Q.empty())
    {
        int u=Q.front();Q.pop_front();
        for(int v = 1;v <= n;v++)
            if(g[u][v] && base[v] != base[u] && match[u] != v)
            {
                if(v == S || (match[v] !=-1 && pre[match[v]] != -1))
                    contract(u,v,n);
                else if(pre[v] == -1)
                {
                    pre[v] = u;
                    if(match[v] != -1) Q.push_back(match[v]),inque[match[v]]=1;
                    else
                    {
                        u = v;
                        while(u != -1)
                        {
                            v = pre[u];
                            int w = match[v];
                            match[u] = v;
                            match[v] = u;
                            u = w;
                        }
                        return 1;
                    }
                }
            }
    }
    return 0;
}
int MMG()
{
    int ans = 0;
    memset(match,-1,sizeof(match));
    for(int i = 1;i <= n;i++)
        if(match[i] == -1 && dfs(i,n)) ans++;
    return ans;
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&n,&m))
    {
        memset(g,0,sizeof(g));
        for(int i = 1;i <= m;i++)
        {
            scanf("%d%d",&a,&b);
            g[a][b] = g[b][a] = 1;
            com[i].u = a;
            com[i].v = b;
        }
        mmg = MMG();
        res.clear();
        for(int i = 1;i <= m;i++)
        {
            a = com[i].u;
            b = com[i].v;
            memset(g,0,sizeof(g));
            for(int j = 1;j <= m;j++)
            if(j != i)
            {
                int x = com[j].u,y = com[j].v;
                if(x == a || x == b || y == a || y == b) continue;
                g[x][y] = g[y][x] = 1;
            }
            int t = MMG();
            if(t != mmg - 1) res.push_back(i);
        }
        printf("%d\n",res.size());
        if(res.size()) printf("%d",res[0]);
        for(int i = 1;i < res.size();i++) printf(" %d",res[i]);
        printf("\n");
    }
    return 0;
}

ural 1099

无向图最大匹配模板题,要求输出方案

#include<bits/stdc++.h>
using namespace std;

const int maxn = 300;
deque<int> Q;
//g[i][j]存放关系图:i,j是否有边,match[i]存放i所匹配的点
bool g[maxn][maxn],inque[maxn],inblossom[maxn],vis[150];
int match[maxn],pre[maxn],base[maxn];
int n,m,mmg;

//找公共祖先
int lca(int u,int v)
{
    bool inpath[maxn]={0};
    while(1)
    {
        u = base[u];
        inpath[u] = 1;
        if(match[u] == -1)break;
        u = pre[match[u]];
    }
    while(1)
    {
        v = base[v];
        if(inpath[v])return v;
        v = pre[match[v]];
    }
}

//压缩花
void reset(int u,int anc)
{
    while(u != anc)
    {
        int v = match[u];
        inblossom[base[u]] = 1;
        inblossom[base[v]] = 1;
        v = pre[v];
        if(base[v] != anc) pre[v] = match[u];
        u = v;
    }
}

void contract(int u,int v,int n)
{
    int anc = lca(u,v);
    memset(inblossom,0,sizeof(inblossom));
    reset(u,anc);reset(v,anc);
    if(base[u] != anc)pre[u] = v;
    if(base[v] != anc)pre[v] = u;
    for(int i = 1;i <= n;i++)
        if(inblossom[base[i]])
        {
            base[i] = anc;
            if(!inque[i])
            {
                Q.push_back(i);
                inque[i] = 1;
            }
        }
}

bool dfs(int S,int n)
{
    for(int i = 0;i <= n;i++)
        pre[i] = -1,inque[i] = 0,base[i] = i;
    Q.clear();Q.push_back(S);inque[S] = 1;
    while(!Q.empty())
    {
        int u = Q.front();Q.pop_front();
        for(int v = 1;v <= n;v++)
            if(g[u][v] && base[v] != base[u] && match[u] != v)
            {
                if(v == S || (match[v] !=-1 && pre[match[v]] != -1))
                    contract(u,v,n);
                else if(pre[v] == -1)
                {
                    pre[v] = u;
                    if(match[v] != -1) Q.push_back(match[v]),inque[match[v]]=1;
                    else
                    {
                        u = v;
                        while(u != -1)
                        {
                            v = pre[u];
                            int w = match[v];
                            match[u] = v;
                            match[v] = u;
                            u = w;
                        }
                        return 1;
                    }
                }
            }
    }
    return 0;
}
int MMG()
{
    int ans = 0;
    memset(match,-1,sizeof(match));
    for(int i = 1;i <= n;i++)
        if(match[i] == -1 && dfs(i,n)) ans++;
    return ans;
}
int main()
{
    int a,b;
    while(~scanf("%d",&n))
    {
        memset(g,0,sizeof(g));
        int i = 0;
        while(~scanf("%d%d",&a,&b))
            g[a][b] = g[b][a] = 1;
        mmg = MMG();
        printf("%d\n",mmg * 2);
        for(int i = 1;i <= n;i++)
            if(i < match[i]) printf("%d %d\n",i,match[i]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值