首先xor类的题目一定要逐位考虑,因为位位之间是不相互影响的
逐位考虑每个点是0还是1,这就转化成了一个这样一个问题
对于每个点可以选择属于S集合(这位是0)或T集合(这位是1)
某些的点对(一条边的两端)属于不同集合会产生一个附加值1(边权)
现在要是附加值最小(边权当前位为1的边最少),并且属于S集合的尽可能多(点权当前位为1尽可能少)
显然第一个问题是一个最小割的问题,对于已经确定这位是什么的点i来说
是0则连边s-->i 容量inf,是1则连边i-->t容量是inf,因为这些点当前位是确定的
然后对一条边(u,v),连边u-->v v-->u 容量都是1,最小割就是最小附加值
这里为什么不用给不确定的点向s,t连边呢?这个我也没有想清楚
反正直观的感受,当一条路径直接或间接连接着则两点一个确定为0,一个确定为1,
那么这条路径最少会产生附加值1,一定要被割断,否则这条路径我一定能使它不产生附加值
下面考虑让属于S的点(这位是0的点)尽可能多
考虑在残流网络上是不存在增广路的,也就是对于一个未确定点i,如果这个点能属于S
那么我从s到i给一个流量,这个流量从点i一定不能流向t,否则就会增大边权和
因此我们只要对于每个未确定的点i在残流网络上顺着剩余容量大于0的边dfs,
只要到不了t,那么这个点就可以属于S(这位为0),否则不行
这样就解决了

  1 const inf=100000007;
  2 type node=record
  3        point,next,flow:longint;
  4      end;
  5 
  6 var edge:array[0..800010] of node;
  7     p,cur,d,a,pre,h,numh:array[0..510] of longint;
  8     v:array[0 ..510] of boolean;
  9     x,y:array[0..2010] of longint;
 10     i,j,n,m,k,len,t,b:longint;
 11     ans1,ans2:int64;
 12 
 13 function min(a,b:longint):longint;
 14   begin
 15     if a>b then exit(b) else exit(a);
 16   end;
 17 
 18 procedure add(x,y,f:longint);
 19   begin
 20     inc(len);
 21     edge[len].point:=y;
 22     edge[len].flow:=f;
 23     edge[len].next:=p[x];
 24     p[x]:=len;
 25   end;
 26 
 27 function sap:longint;
 28   var u,i,j,tmp,neck,q:longint;
 29   begin
 30     fillchar(h,sizeof(h),0);
 31     fillchar(numh,sizeof(numh),0);
 32     numh[0]:=t+1;
 33     u:=0;
 34     for i:=0 to t do
 35       cur[i]:=p[i];
 36     neck:=inf;
 37     sap:=0;
 38     while h[0]<t+1 do
 39     begin
 40       d[u]:=neck;
 41       i:=cur[u];
 42       while i<>-1 do
 43       begin
 44         j:=edge[i].point;
 45         if (edge[i].flow>0) and (h[u]=h[j]+1) then
 46         begin
 47           pre[j]:=u;
 48           cur[u]:=i;
 49           neck:=min(neck,edge[i].flow);
 50           u:=j;
 51           if u=t then
 52           begin
 53             sap:=sap+neck;
 54             while u<>0 do
 55             begin
 56               u:=pre[u];
 57               j:=cur[u];
 58               dec(edge[j].flow,neck);
 59               inc(edge[j xor 1].flow,neck);
 60             end;
 61             neck:=inf;
 62           end;
 63           break;
 64         end;
 65         i:=edge[i].next;
 66       end;
 67       if i=-1 then
 68       begin
 69         dec(numh[h[u]]);
 70         if numh[h[u]]=0 then exit;
 71         tmp:=t;
 72         q:=-1;
 73         i:=p[u];
 74         while i<>-1 do
 75         begin
 76           j:=edge[i].point;
 77           if edge[i].flow>0 then
 78             if h[j]<tmp then
 79             begin
 80               tmp:=h[j];
 81               q:=i;
 82             end;
 83           i:=edge[i].next;
 84         end;
 85         h[u]:=tmp+1;
 86         cur[u]:=q;
 87         inc(numh[h[u]]);
 88         if u<>0 then
 89         begin
 90           u:=pre[u];
 91           neck:=d[u];
 92         end;
 93       end;
 94     end;
 95   end;
 96 
 97 function dfs(x:longint):boolean;
 98   var i,y:longint;
 99   begin
100     v[x]:=true;
101     if x=t then exit(true);
102     i:=p[x];
103     while i<>-1 do
104     begin
105       y:=edge[i].point;
106       if (edge[i].flow>0) and not v[y] then
107         if dfs(y) then exit(true);
108       i:=edge[i].next;
109     end;
110     exit(false);
111   end;
112 
113 begin
114   readln(n,m);
115   b:=0;
116   for i:=1 to n do
117   begin
118     readln(a[i]);
119     if (a[i]>0) and (trunc(ln(a[i])/ln(2))>b) then
120       b:=trunc(ln(a[i])/ln(2)); //显然比以确定点的最大位数还大的位直接取0即可
121     if a[i]>0 then ans2:=ans2+a[i];
122   end;
123   for i:=1 to m do
124     readln(x[i],y[i]);
125   t:=n+1;
126   for i:=0 to b do
127   begin
128     len:=-1;
129     fillchar(p,sizeof(p),255);
130     for j:=1 to n do
131       if a[j]>=0 then
132       begin
133         if a[j] and (1 shl i)=0 then
134         begin
135           add(0,j,inf);
136           add(j,0,0);
137         end
138         else begin
139           add(j,t,inf);
140           add(t,j,0);
141         end;
142       end;
143     for j:=1 to m do
144     begin
145       add(x[j],y[j],1);
146       add(y[j],x[j],0);
147       add(y[j],x[j],1);
148       add(x[j],y[j],0);
149     end;
150     ans1:=ans1+int64(sap)*int64(1 shl i);  //1 shl i是这位位权
151     for j:=1 to n do
152       if a[j]<0 then
153       begin
154         fillchar(v,sizeof(v),false);
155         if dfs(j) then ans2:=ans2+1 shl i;  //能访问到t则这个点当前位不能为0
156       end;
157   end;
158   writeln(ans1);
159   writeln(ans2);
160 end.
View Code

 

posted on 2014-12-25 13:30  acphile  阅读(190)  评论(0编辑  收藏  举报