终于忙完期末考试了,即将进入愉快的暑假(虽然暑假作业奇多,但好歹终于能有大量时间刷题了)
先把上次新一类最小割留下的一道题目A了复习一下;
题目看起来很复杂,实际上和bzoj2132是同一个类型的
用S集合表示放正能量,T集合表示放负能量(可自行参照上一篇文章)
只是有几个不同点:
-
有些点是已经确定为S或T集合中的点
-
选择点属于S或者属于T都是没有收益的
对于未知的问题我们要转化为已知的问题来求解
首先我们来处理2,考虑到割是我们所得不到的收益,
于是我们可以把每个点选择属于S或者属于T产生的收益都当做是个1,
也就是对于每个点i,连接s--->i, i--->t 容量为1;
最后ans=n*n*n(抵消我们之前强加的收益)+图中的边数-mincut;
下面就是1没有解决了,考虑到割是我们所得不到的收益,
所以,对于那些已经确定为S集合中的点(T集合同理),我们只要使
s--->i 容量为inf,也就让这条边一定不成为割边,那么就满足了这个点的确定性;
好了,即使是立体的,依然可以黑白染色划分二分图,所以其余实现细节类似bzoj2132,这里不加赘述。
1 const inf=100000007; 2 dx:array[1..6] of integer=(-1,1,0,0,0,0); 3 dy:array[1..6] of integer=(0,0,-1,1,0,0); 4 dz:array[1..6] of integer=(0,0,0,0,-1,1); 5 type node=record 6 next,flow,point:longint; 7 end; 8 9 var edge:array[0..2000010] of node; 10 h,numh,p,cur,d,pre:array[0..64010] of longint; 11 num:array[0..41,0..41,0..41] of longint; 12 t,len,i,j,n,k,x,y,z,m,ans,sum:longint; 13 s:ansistring; 14 15 function min(a,b:longint):longint; 16 begin 17 if a>b then exit(b) else exit(a); 18 end; 19 20 procedure add(x,y,f:longint); 21 begin 22 inc(len); 23 edge[len].point:=y; 24 edge[len].flow:=f; 25 edge[len].next:=p[x]; 26 p[x]:=len; 27 end; 28 29 function sap:longint; 30 var u,i,j,q,neck,tmp:longint; 31 begin 32 numh[0]:=t+1; 33 for i:=0 to t do 34 cur[i]:=p[i]; 35 u:=0; 36 sap:=0; 37 neck:=inf; 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 cur[u]:=i; 48 pre[j]:=u; 49 neck:=min(neck,edge[i].flow); 50 u:=j; 51 if u=t then 52 begin 53 while u<>0 do 54 begin 55 u:=pre[u]; 56 i:=cur[u]; 57 dec(edge[i].flow,neck); 58 inc(edge[i xor 1].flow,neck); 59 end; 60 sap:=sap+neck; 61 end; 62 break; 63 end; 64 i:=edge[i].next; 65 end; 66 if i=-1 then 67 begin 68 dec(numh[h[u]]); 69 if numh[h[u]]=0 then exit; 70 tmp:=t; 71 i:=p[u]; 72 q:=-1; 73 while i<>-1 do 74 begin 75 j:=edge[i].point; 76 if (edge[i].flow>0) and (h[j]<tmp) then 77 begin 78 q:=i; 79 tmp:=h[j]; 80 end; 81 i:=edge[i].next; 82 end; 83 h[u]:=tmp+1; 84 inc(numh[h[u]]); 85 cur[u]:=q; 86 if u<>0 then 87 begin 88 u:=pre[u]; 89 neck:=d[u]; 90 end; 91 end; 92 end; 93 end; 94 95 begin 96 len:=-1; 97 fillchar(p,sizeof(p),255); 98 readln(n); 99 t:=n*n*n+1; 100 for i:=1 to n do 101 begin 102 for j:=1 to n do 103 begin 104 readln(s); 105 for k:=1 to n do 106 begin 107 inc(m); 108 num[i,j,k]:=m; 109 if (s[k]='N') and ((i+j+k) mod 2=1) or (s[k]='P') and ((i+j+k) mod 2=0) then 110 begin 111 add(0,m,inf); 112 add(m,0,0); 113 add(m,t,1); 114 add(t,m,0); 115 end 116 else if (s[k]='N') and ((i+j+k) mod 2=0) or (s[k]='P') and ((i+j+k) mod 2=1) then 117 begin 118 add(m,t,inf); 119 add(t,m,0); 120 add(0,m,1); 121 add(m,0,0); 122 end 123 else if s[k]='?' then 124 begin 125 add(0,m,1); 126 add(m,0,0); 127 add(m,t,1); 128 add(t,m,0); 129 end; 130 end; 131 end; 132 if i<>n then readln; 133 end; 134 for i:=1 to n do 135 for j:=1 to n do 136 for k:=1 to n do 137 for m:=1 to 6 do 138 begin 139 x:=i+dx[m]; 140 y:=j+dy[m]; 141 z:=k+dz[m]; 142 if num[x,y,z]>0 then 143 begin 144 add(num[i,j,k],num[x,y,z],1); 145 add(num[x,y,z],num[i,j,k],0); 146 inc(sum); 147 end; 148 end; 149 sum:=sum div 2+n*n*n; 150 writeln(sum-sap); 151 end.