BZOJ2400: Spoj 839 Optimal Marks
Description
定义无向图中的一条边的值为:这条边连接的两个点的值的异或值。
定义一个无向图的值为:这个无向图所有边的值的和。
给你一个有n个结点m条边的无向图。其中的一些点的值是给定的,而其余的点的值由你决定(但要求均为非负数),使得这个无向图的值最小。在无向图的值最小的前提下,使得无向图中所有点的值的和最小。
Input
第一行,两个数n,m,表示图的点数和边数。
接下来n行,每行一个数,按编号给出每个点的值(若为负数则表示这个点的值由你决定,值的绝对值大小不超过10^9)。
接下来m行,每行二个数a,b,表示编号为a与b的两点间连一条边。(保证无重边与自环。)
Output
第一行,一个数,表示无向图的值。
第二行,一个数,表示无向图中所有点的值的和。
Sample Input
3 2
2
-1
0
1 2
2 3
2
-1
0
1 2
2 3
Sample Output
2
2
2
HINT
数据约定
n<=500,m<=2000
样例解释
2结点的值定为0即可。
经典的最小割建模。
先按位处理,然后规定S割的节点表示选1,T割的节点表示选0。
然后对那些权值固定的点强制连上inf,无向图的边也连上,最小割即可。
第二问就是S割中的节点个数。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=510; const int maxm=10010; const int inf=1e9; struct Dinic { int n,m,s,t,cur[maxn],d[maxn],vis[maxn],clo; int first[maxn],next[maxm]; struct Edge {int from,to,flow;}edges[maxm]; void init(int n) { this->n=n;m=0; memset(first,-1,sizeof(first)); } void AddEdge(int u,int v,int w) { edges[m]=(Edge){u,v,w};next[m]=first[u];first[u]=m++; edges[m]=(Edge){v,u,0};next[m]=first[v];first[v]=m++; } int Q[maxn]; int BFS() { int l=0,r=0;Q[r++]=s;vis[s]=++clo; while(l!=r) { int x=Q[l++];cur[x]=first[x]; ren { Edge& e=edges[i]; if(e.flow&&vis[e.to]!=clo) { vis[e.to]=clo; d[e.to]=d[x]+1; Q[r++]=e.to; } } } return vis[t]==clo; } int DFS(int x,int a) { if(x==t||!a) return a; int flow=0,f; for(int& i=cur[x];i!=-1;i=next[i]) { Edge& e=edges[i]; if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.flow)))) { e.flow-=f;edges[i^1].flow+=f; flow+=f;a-=f;if(!a) break; } } return flow; } int solve(int s,int t) { this->s=s;this->t=t;int flow=0; while(BFS()) flow+=DFS(s,1e9); return flow; } int solve2() { BFS();int res=-1; rep(i,1,n) if(vis[i]==clo) res++; return res; } }sol; typedef long long ll; int val[maxn],u[maxm],v[maxm]; ll ans,ans2; int main() { int n=read(),m=read(); rep(i,1,n) val[i]=read(); rep(i,1,m) u[i]=read(),v[i]=read(); rep(i,0,30) { int S=n+1,T=n+2,sum=0;sol.init(T); rep(j,1,n) if(val[j]>=0) { if(val[j]>>i&1) sol.AddEdge(S,j,inf); else sol.AddEdge(j,T,inf); } rep(j,1,m) sol.AddEdge(u[j],v[j],1),sol.AddEdge(v[j],u[j],1); ans+=(1ll<<i)*sol.solve(S,T); ans2+=(1ll<<i)*sol.solve2(); } printf("%lld\n%lld\n",ans,ans2); return 0; }