这是《最小割模型在信息学竞赛中的应用》里的一道例题。
从二进制考虑,每个二进制位都用最小割来求解。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=505,M=3005,INF=0x3f3f3f3f; const int mxN=N,mxM=M*4+2*N; int n,m; int lx[M],ly[M]; int v[N]; bool mk[N]; int p; struct graph{ int S,T; int base[mxN],vec[mxM],pre[mxM],tot; int c[mxM]; int d[mxN],q[mxN]; bool vis[mxN]; void init() { memset(base,0,sizeof(base)); tot=1; } void link(int x,int y,int z) { vec[++tot]=y; pre[tot]=base[x]; base[x]=tot; c[tot]=z; vec[++tot]=x; pre[tot]=base[y]; base[y]=tot; c[tot]=0; } void build() { S=0; T=n+1; for (int i=1;i<=m;i++) link(lx[i],ly[i],1),link(ly[i],lx[i],1); for (int i=1;i<=n;i++) { if (!mk[i]) continue; if (v[i]&1<<p) link(S,i,INF); else link(i,T,INF); } } void update(int u) { vis[u]=1; v[u]|=1<<p; for (int now=base[u];now;now=pre[now]) { int v=vec[now]; if (vis[v]||c[now]==0) continue; update(v); } } void work() { for (int i=S;i<=T;i++) vis[i]=0; update(S); } bool bfs() { int head=0,tail=0; memset(d,-1,sizeof(d)); d[S]=0; q[++tail]=S; while(head<tail) { head++; int u=q[head]; for (int now=base[u];now;now=pre[now]) { int v=vec[now]; if (d[v]==-1&&c[now]>0) { d[v]=d[u]+1; q[++tail]=v; if (v==T) return 1; } } } return 0; } int dfs(int u,int flow) { int r=0; if (u==T) return flow; for (int now=base[u];now&&r<flow;now=pre[now]) { int v=vec[now]; if (c[now]>0&&d[v]==d[u]+1) { int x=min(c[now],flow-r); x=dfs(v,x); r+=x; c[now]-=x; c[now^1]+=x; } } if (!r)d[u]=-2; return r; } int dinic() { int ans=0; while(bfs()) ans+=dfs(S,INF); return ans; } }G; void read() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) mk[i]=0,v[i]=0; for (int i=1;i<=m;i++) scanf("%d%d",&lx[i],&ly[i]); int k; scanf("%d",&k); for (int i=1;i<=k;i++) { int x; scanf("%d",&x); mk[x]=1; scanf("%d",&v[x]); } } int main() { int t; scanf("%d",&t); while(t--) { read(); for (p=0;p<31;p++) { G.init(); G.build(); G.dinic(); G.work(); } for (int i=1;i<=n;i++) printf("%d\n",v[i]); } }