HDU 4687 Boke and Tsukkomi(一般图匹配+枚举)

来源:互联网 发布:vb case语句的用法 编辑:程序博客网 时间:2024/06/10 14:55

Boke and Tsukkomi

Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)
Total Submission(s): 1232    Accepted Submission(s): 394


Problem Description
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 ≤ Ti ≤ N, where Bi != Ti.
 

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 41 32 32 43 16 61 23 23 45 25 45 6
 

Sample Output
1232 4 5
 

Author
Zejun Wu (watashi)
 

Source
2013 Multi-University Training Contest 9 
 

Recommend
zhuyuanchen520

解题思路:

    告诉你一个一般图的匹配情况,问哪些匹配是一定不能使用的。


解题思路:

    常见的枚举是问哪些是必须的,这样可以删边再跑一遍得到答案。这题反过来问哪些是一定不能用,就要强制他们匹配,就可以同时删掉这两个点,看最大匹配是否是原最大匹配-1。


AC代码:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <ctime>#include <vector>#include <stack>#include <deque>#include <string>#include <map>using namespace std;#define INF 0x3f3f3f3f#define LL long long#define fi first#define se second#define mem(a,b) memset((a),(b),sizeof(a))const int MAXV=40+3;const int MAXE=123+3;int V,E;//点的个数,点的编号从1到Vpair<int,int> edge[MAXE];//存边bool G[MAXV][MAXV];int match[MAXV];bool inqueue[MAXV],inpath[MAXV],inblossom[MAXV];int  head,tail;int queue[MAXV];int start,finish;int newbase;int father[MAXV],base[MAXV];int Count;//匹配点数,匹配对数是Count/2vector<int> save;void Push(int u){    queue[tail]=u;    ++tail;    inqueue[u]=true;}int Pop(){    int res=queue[head];    head++;    return res;}int findCommonAncestor(int u,int v){    mem(inpath,0);    while(true)    {        u=base[u];        inpath[u]=true;        if(u==start)            break;        u=father[match[u]];    }    while(true)    {        v=base[v];        if(inpath[v])            break;        v=father[match[v]];    }    return v;}void resetTrace(int u){    int v;    while(base[u]!=newbase)    {        v=match[u];        inblossom[base[u]]=inblossom[base[v]]=true;        u=father[v];        if(base[u]!=newbase)            father[u]=v;    }}void bloosomContract(int u,int v){    newbase=findCommonAncestor(u,v);    mem(inblossom,0);    resetTrace(u);    resetTrace(v);    if(base[u]!=newbase)        father[u]=v;    if(base[v]!=newbase)        father[v]=u;    for(int tu=1;tu<=V;++tu)        if(inblossom[base[tu]])        {            base[tu]=newbase;            if(!inqueue[tu])                Push(tu);        }}void findAugmentingPath(){    mem(inqueue,0);    mem(father,0);    for(int i=1;i<=V;++i)        base[i]=i;    head=tail=1;    Push(start);    finish=0;    while(head<tail)    {        int u=Pop();        for(int v=1;v<=V;++v)            if(G[u][v]&&(base[u]!=base[v])&&(match[u]!=v))            {                if((v==start)||((match[v]>0)&&father[match[v]]>0))                    bloosomContract(u,v);                else if(father[v]==0)                {                    father[v]=u;                    if(match[v]>0)                        Push(match[v]);                    else                    {                        finish=v;                        return ;                    }                                    }            }    }}void augmentPath(){    int u,v,w;    u=finish;    while(u>0)    {        v=father[u];        w=match[v];        match[v]=u;        match[u]=v;        u=w;    }}void edmonds()//带花树求一般图最大匹配{    mem(match,0);    for(int u=1;u<=V;++u)        if(match[u]==0)        {            start=u;            findAugmentingPath();            if(finish>0)                augmentPath();        }}int get_ans()//得到匹配人数{    Count=0;    for(int u=1;u<=V;++u)        if(match[u]>0)            ++Count;    return Count;}int main(){    while(~scanf("%d%d",&V,&E))    {        mem(G,0);        save.clear();        for(int i=0;i<E;++i)        {            scanf("%d%d",&edge[i].fi,&edge[i].se);            G[edge[i].fi][edge[i].se]=G[edge[i].se][edge[i].fi]=true;        }        edmonds();        int the_max=get_ans();        for(int i=0;i<E;++i)//枚举强制匹配的边        {            mem(G,0);            for(int j=0;j<E;++j)            {                int u=edge[j].fi,v=edge[j].se;                if(u==edge[i].fi||u==edge[i].se||v==edge[i].fi||v==edge[i].se)//已经被删掉                    continue;                G[u][v]=G[v][u]=true;            }            edmonds();//求最大匹配            if(get_ans()+2!=the_max)//得到的是匹配的点数,所以要+2                save.push_back(i+1);        }        printf("%d\n",(int)save.size());        for(int i=0;i<(int)save.size();++i)        {            printf("%d",save[i]);            if(i==(int)save.size()-1)                putchar('\n');            else putchar(' ');        }    }        return 0;}

原创粉丝点击