闵神讲网络流应用的例题,来水一水
要写出这道题,需要深入理解两个概念,异或和最小割。
异或具有相对独立性,所以我们把每一位拆开来看,即做大概$32$次最小割。然后累加即可。
然后是最小割把一张图分割成两个集合,简单看就是0集合和1集合。
简单的建图:
原图不变,改成双向边,所有的流量限制为1。然后所有S点向点权为1的连边,点权为0的向T连边,容量都是正无穷。
为什么这样建?首先看,最小割把一张图分成两个点集。而因为我们的流量限制可以让最小割只割真实存在的边,而割的也只有可能是跨越0集合和1集合的边。所以最后的最小割就是答案。
//SPOJ839 //by Cydiater //2017.1.15 #include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <cstdlib> #include <iomanip> #include <queue> #include <map> #include <algorithm> #include <cstring> #include <string> #include <bitset> #include <set> #include <vector> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) #define cmax(a,b) a=max(a,b) #define cmin(a,b) a=min(a,b) #define Auto(i,node) for(int i=LINK[node];i;i=e[i].next) #define vci vector<int> const int MAXN=1e4+5; const int oo=0x3f3f3f3f; inline int read(){ char ch=getchar();int x=0,f=1; while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int LINK[MAXN],len=0,N,M,Val[MAXN],TT,Q,tag[MAXN],S,T,ans=0,q[MAXN],head,tail,level[MAXN]; bool used[MAXN],vis[MAXN]; vci E[MAXN]; struct edge{ int x,y,next,flow,reverse; }e[MAXN<<1]; namespace solution{ void Clear(){ len=0; memset(LINK,0,sizeof(LINK)); } inline void insert(int x,int y,int flow,int delta){ e[++len].next=LINK[x];LINK[x]=len;e[len].y=y; e[len].flow=flow;e[len].reverse=len+delta; } void Prepare(){ Clear(); N=read();M=read(); S=N+1;T=N+2; up(i,1,N)E[i].clear(); up(i,1,M){ int x=read(),y=read(); E[x].push_back(y); E[y].push_back(x); } Q=read(); memset(Val,0,sizeof(Val)); memset(used,0,sizeof(used)); while(Q--){ int node=read(),val=read(); Val[node]=val;used[node]=1; } } void Build(){ Clear(); up(i,1,N){ int siz=E[i].size(); up(j,0,siz-1){ insert(i,E[i][j],1,1); insert(E[i][j],i,0,-1); } } up(i,1,N){ if(tag[i]==1){ insert(S,i,oo,1); insert(i,S,0,-1); }else if(tag[i]==0){ insert(i,T,oo,1); insert(T,i,0,-1); } } } bool makelevel(){ memset(level,-1,sizeof(level)); head=1;tail=0;level[S]=0;q[++tail]=S; for(;head<=tail;head++){ int node=q[head]; Auto(i,node)if(e[i].flow>0&&level[e[i].y]==-1){ level[e[i].y]=level[node]+1; q[++tail]=e[i].y; } } return level[T]!=-1; } int addflow(int node,int flow){ if(node==T) return flow; int maxflow=0,d=0; Auto(i,node)if(level[e[i].y]==level[node]+1&&e[i].flow>0){ if(d=addflow(e[i].y,min(e[i].flow,flow-maxflow))){ maxflow+=d; e[i].flow-=d; e[e[i].reverse].flow+=d; } } if(maxflow==0)level[node]=-1; return maxflow; } void Dinic(int dig){ int d; while(makelevel()) while(d=addflow(S,oo)) ans+=(d<<dig); } void DFS(int node){ vis[node]=1;tag[node]=1; Auto(i,node)if(e[i].flow>0&&!vis[e[i].y]) DFS(e[i].y); } void Solve(){ up(dig,0,31){ up(i,1,N){ if(used[i]) tag[i]=((Val[i]&(1<<dig))>>dig); else tag[i]=-1; } Build(); Dinic(dig); up(i,1,N)tag[i]=0; memset(vis,0,sizeof(vis)); DFS(S); up(i,1,N)if(!used[i])Val[i]|=(tag[i]<<dig); } up(i,1,N)printf("%d\n",Val[i]); } } int main(){ //freopen("input.in","r",stdin); using namespace solution; TT=read(); while(TT--){ Prepare(); Solve(); } return 0; }
时间: 2024-10-31 15:35:35