Benelux Algorithm Programming Contest 2016 Preliminary K. Translators’ Dinner(思路)

题意:

n种语言,m个翻译官,每个翻译官会2种语言,会同一种语言的2个翻译官可以放在一组

问能否将所有的翻译官两两配对

输出方案

n<=100 m<=200

保证没有2个翻译官会完全相同的2种语言

 

 

我看了半天题解没看懂

大佬分分钟用另一种思路秒杀题解

tqltqltql%%%%%%%%%%%%%

 

将语言看做点,翻译官看作边

构图之后,如果每个连通块都是偶数条边,那么一定有一种解的方案

考虑为每一个连通块构造方案

枚举其中一条边,枚举它的配对边

如果删去这两条边后,剩余的点和边仍然满足每个连通块都是偶数条边,即仍然有解的方案

那就找到了它的匹配边

 

复杂度是三次方级别的

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 

#include<cstdio>
#include<cstring>
 
using namespace std;

#define N 101
#define M 201

int n,m;
int a[M],b[M],d[N];
bool cut[M];

int f[N];
int siz[N];

bool doo[N];
int match[M];

int ff[N];

int find(int i) { return f[i]==i ? i : f[i]=find(f[i]); }

int find2(int i) { return ff[i]==i ? i : ff[i]=find2(ff[i]); }

bool judge()
{
    for(int i=1;i<=n;++i) ff[i]=i;
    memset(siz,0,sizeof(siz));
    memset(d,0,sizeof(d));
    int p,q;
    for(int i=1;i<=m;++i)
        if(!cut[i])
        {
            d[a[i]]++;
            d[b[i]]++;
            p=find2(a[i]);
            q=find2(b[i]);    
            ff[p]=q;
        }
    for(int i=1;i<=n;++i) siz[find2(i)]+=d[i];
    for(int i=1;i<=n;++i)
        if(find2(i)==i && siz[i]/2&1) return false;
    return true; 
}

int solve(int x)
{
    for(int i=1;i<=m;++i)
        if(i!=x && !match[i])
            if(a[x]==a[i] || a[x]==b[i] || b[x]==a[i] || b[x]==b[i])
            {
                cut[x]=cut[i]=true;
                if(judge()) return i;
                cut[x]=cut[i]=false;
            }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) f[i]=i;
    int fa,fb;
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&a[i],&b[i]);
        ++a[i];
        ++b[i];
        d[a[i]]++;
        d[b[i]]++;
        fa=find(a[i]);
        fb=find(b[i]);
        f[fa]=fb;
    }
    for(int i=1;i<=n;++i)
        siz[find(i)]+=d[i];
    for(int i=1;i<=n;++i)
        if(find(i)==i && siz[i]/2&1 )
        {
            printf("impossible");
            return 0;
        }
    int g;
    for(int i=1;i<=n;++i)
        if(f[i]==i)
        {
            for(int j=1;j<=n;++j)
                if(f[j]==i) doo[j]=true;
            for(int j=1;j<=m;++j)
                if(!match[j] && doo[a[j]] && doo[b[j]])
                {
                    g=solve(j);
                    match[j]=g;
                    match[g]=j;
                }
            memset(doo,false,sizeof(doo));
        }
    for(int i=1;i<=m;++i)
        if(i<match[i]) printf("%d %d\n",i-1,match[i]-1);    
}

 

posted @ 2020-09-09 20:44  TRTTG  阅读(346)  评论(2编辑  收藏  举报