[bzoj4405][wc2016]挑战NPC
来自FallDream的博客,未经允许,请勿转载,谢谢。
小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目:
有n个球,用整数1到n编号。还有m个筐子,用整数1到m编号。
每个筐子最多能装3个球。
每个球只能放进特定的筐子中。具体有e个条件,第i个条件用两个整数vi和ui描述,表示编号为vi的球可以放进编号为ui的筐子中。
每个球都必须放进一个筐子中。如果一个筐子内有不超过1个球,那么我们称这样的筐子为半空的。
求半空的筐子最多有多少个,以及在最优方案中,每个球分别放在哪个筐子中。
小N看到题目后瞬间没了思路,站在旁边看热闹的小I嘿嘿一笑:“水题!”
然后三言两语道出了一个多项式算法。
小N瞬间就惊呆了,三秒钟后他回过神来一拍桌子:
“不对!这个问题显然是NP完全问题,你算法肯定有错!”
小I浅笑:“所以,等我领图灵奖吧!”
小O只会出题不会做题,所以找到了你——请你对这个问题进行探究,并写一个程序解决此题。
T<=5 n<=300 m<=100
考虑每个筐子拆成3个点,在被匹配走0/1/2/3个点的情况下能够产生的最大匹配和想要的贡献相同
只需要在其中两个点之间连一条边就好啦
然后带花树
其实我是想贴个模板
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define MN 600 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int head[MN+5],vis[MN+5],cnt=0,n,m,Q,q[MN*MN],now=0,mark[MN+5],match[MN+5],ne[MN+5],fa[MN+5],top,tail; struct edge{int to,ne;}e[MN*MN+5]; inline int getfa(int x){return !fa[x]?x:fa[x]=getfa(fa[x]);} inline void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } int Lca(int x,int y) { ++now; for(;;swap(x,y)) if(x!=-1) { x=getfa(x); if(vis[x]==now) return x; vis[x]=now; if(match[x]) x=ne[match[x]]; else x=-1; } } void Unit(int x,int y) { x=getfa(x);y=getfa(y); if(x!=y) fa[x]=y; } void group(int a,int p) { for(;a!=p;) { int b=match[a],c=ne[b]; if(getfa(c)!=p) ne[c]=b; if(mark[b]==2) mark[q[++top]=b]=1; if(mark[c]==2) mark[q[++top]=c]=1; Unit(a,b);Unit(b,c); a=c; } } void Solve(int x) { for(int i=1;i<=n+3*m;++i) ne[i]=fa[i]=mark[i]=vis[i]=0; mark[x]=1;q[top=tail=0]=x; for(;!match[x]&&top>=tail;++tail) { int y=q[tail]; for(int i=head[y];i;i=e[i].ne) { int v=e[i].to; if(match[y]==v||mark[v]==2||getfa(y)==getfa(v)) continue; if(mark[v]==1) { int lca=Lca(y,v); if(getfa(y)!=lca) ne[y]=v; if(getfa(v)!=lca) ne[v]=y; group(y,lca); group(v,lca); } else if(!match[v]) { ne[v]=y; for(int u=v;u;) { int w=ne[u],ww=match[w]; match[w]=u,match[u]=w; u=ww; } return; } else { ne[v]=y; mark[q[++top]=match[v]]=1; mark[v]=2; } } } } int main() { for(int T=read();T;--T) { memset(head,0,sizeof(head)); memset(match,0,sizeof(match));cnt=0; n=read();m=read();Q=read(); for(int i=1;i<=Q;++i) { int x=read(),y=read(); ins(x,y+n);ins(x,y+n+m);ins(x,y+n+m+m); } for(int i=1;i<=m;++i) ins(i+n,i+n+m); for(int i=1;i<=n+3*m;++i) if(!match[i]) Solve(i); int ans=0; for(int i=1;i<=n+3*m;++i) if(match[i]) ++ans; printf("%d\n",(ans>>1)-n); } return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream