题意:
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 ",i-1,match[i]-1); }