【bzoj2400】Spoj 839 Optimal Marks 按位最大流
Spoj 839 Optimal Marks
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 908 Solved: 347
[Submit][Status][Discuss]
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即可。
因为是xor,可以从按位的思考
这种两个答案的,二维偏序差不多,一般会想到费用流,
但是这里可以是图的权值扩大到点权和到达不了的状态,即不由点权和影响。
这样/mx 为图的权值,%mx为点的权和。
然后考虑建图,设S为0集合,T为1集合,所以只需要考虑边两个端点一个选S,一个选T这样才会产生值。
看限制了,如果当前这位有值,那么就按这个赋值,如果是1,那么S-i为inf,i-T为1;
这样的,边的话,就是10000的边。
具体看代码。
每次的最大流的意义不同,代表1<<i。
1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<cstdio> 5 #include<algorithm> 6 #include<queue> 7 8 #define inf 1000000007 9 #define ll long long 10 #define N 507 11 #define M 20007 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 17 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 21 int n,m,S,T; 22 int num[N]; 23 int cnt,hed[N],nxt[M],rea[M],val[M],cur[N]; 24 int dis[N]; 25 ll ans1,ans2; 26 struct Node 27 { 28 int x,y; 29 }a[M]; 30 31 void add(int u,int v,int w) 32 { 33 nxt[++cnt]=hed[u]; 34 hed[u]=cnt; 35 rea[cnt]=v; 36 val[cnt]=w; 37 } 38 void add_two_edge(int u,int v,int w) 39 { 40 add(u,v,w); 41 add(v,u,0); 42 } 43 void build(int x) 44 { 45 memset(hed,-1,sizeof(hed)),cnt=1; 46 for (int i=1;i<=n;i++) 47 if (num[i]<0) add_two_edge(i,T,1); 48 else 49 { 50 if (num[i]&(1<<x))add_two_edge(S,i,inf),add_two_edge(i,T,1); 51 else add_two_edge(i,T,inf); 52 } 53 for (int i=1;i<=m;i++) 54 add_two_edge(a[i].x,a[i].y,10000), 55 add_two_edge(a[i].y,a[i].x,10000); 56 } 57 bool bfs() 58 { 59 for (int i=S;i<=T;i++)dis[i]=-1; 60 dis[S]=0; 61 queue<int>q;q.push(S); 62 while(!q.empty()) 63 { 64 int u=q.front();q.pop(); 65 for (int i=hed[u];i!=-1;i=nxt[i]) 66 { 67 int v=rea[i],fee=val[i]; 68 if (dis[v]!=-1||!fee)continue; 69 dis[v]=dis[u]+1; 70 if (v==T)return 1; 71 q.push(v); 72 } 73 } 74 return 0; 75 } 76 ll dfs(int u,int MX) 77 { 78 ll res=0; 79 if (MX==0||u==T)return MX; 80 for (int i=cur[u];i!=-1;i=nxt[i]) 81 { 82 int v=rea[i],fee=val[i]; 83 if (dis[v]!=dis[u]+1)continue; 84 int x=dfs(v,min(MX,fee)); 85 cur[u]=i,res+=x,MX-=x; 86 val[i]-=x,val[i^1]+=x; 87 if (MX==0) break; 88 } 89 if (!res)dis[u]=-1; 90 return res; 91 } 92 ll dinic() 93 { 94 ll res=0; 95 while(bfs()) 96 { 97 for (int i=S;i<=T;i++)cur[i]=hed[i]; 98 res+=dfs(0,inf); 99 } 100 return res; 101 } 102 int main() 103 { 104 n=read(),m=read(),S=0,T=n+1;int mx=-1; 105 for (int i=1;i<=n;i++) 106 { 107 num[i]=read(); 108 mx=max(mx,num[i]); 109 } 110 for (int i=1;i<=m;i++)a[i].x=read(),a[i].y=read(); 111 for (int i=0;(1<<i)<=mx;i++) 112 { 113 build(i); 114 ll res=dinic(); 115 ans1+=(res/10000)*(ll)(1<<i); 116 ans2+=(res%10000)*(ll)(1<<i); 117 } 118 printf("%lld\n%lld\n",ans1,ans2); 119 }