【BZOJ1976】[BeiJing2010组队]能量魔方 Cube 最小割
【BZOJ1976】[BeiJing2010组队]能量魔方 Cube
Description
小C 有一个能量魔方,这个魔方可神奇了,只要按照特定方式,放入不同的 能量水晶,就可以产生巨大的能量。 能量魔方是一个 N*N*N 的立方体,一共用 N3 个空格可以填充能量水晶。 能量水晶有两种: ·一种是正能量水晶(Positive) ·一种是负能量水晶(Negative) 当这个魔方被填满后,就会依据填充的能量水晶间的关系产生巨大能量。对 于相邻两(相邻就是拥有同一个面)的两个格子,如果这两个格子填充的是一正一 负两种水晶,就会产生一单位的能量。而整个魔方的总能量,就是这些产生的能 量的总和。 现在,小 C 已经在魔方中填充了一些水晶,还有一些位置空着。他想知道, 如果剩下的空格可以随意填充,那么在最优情况下,这个魔方可以产生多少能量。
Input
第一行包含一个数N,表示魔方的大小。 接下来 N2 行,每行N个字符,每个字符有三种可能: P:表示此方格已经填充了正能量水晶; N:表示此方格已经填充了负能量水晶; ?:表示此方格待填充。 上述 N*N 行,第(i-1)*N+1~i*N 行描述了立方体第 i 层从前到后,从左到右的 状态。且每 N 行间,都有一空行分隔。
Output
仅包含一行一个数,表示魔方最多能产生的能量
Sample Input
2
P?
??
??
N?
P?
??
??
N?
Sample Output
9
HINT
如下状态时,可产生最多的能量。
PN
NP
NP
NN
【数据规模】
10% 的数据N≤3;
30% 的数据N≤4;
80% 的数据N≤10;
100% 的数据N≤40。
题解:经典的最小割模型,只不过变成了三维的。先黑白染色,然后黑色的点翻转源汇,具体方法:
1.S ->i 容量为i周围已确定的N个数
2.i -> T 容量为i周围已确定的P个数
上面2条边要翻转源汇
3.i <-> j 容量1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; int n,ans,cnt,tot,S,T; int dx[]={0,0,0,0,1,-1},dy[]={0,0,1,-1,0,0},dz[]={1,-1,0,0,0,0}; int map[50][50][50],to[2000000],next[2000000],val[2000000],d[100000],head[100000]; char str[50]; queue< int > q; int dfs( int x, int mf) { if (x==T) return mf; int i,k,temp=mf; for (i=head[x];i!=-1;i=next[i]) if (d[to[i]]==d[x]+1&&val[i]) { k=dfs(to[i],min(temp,val[i])); if (!k) d[to[i]]=0; val[i]-=k,val[i^1]+=k,temp-=k; if (!temp) break ; } return mf-temp; } int bfs() { while (!q.empty()) q.pop(); memset (d,0, sizeof (d)); int i,u; q.push(S),d[S]=1; while (!q.empty()) { u=q.front(),q.pop(); for (i=head[u];i!=-1;i=next[i]) { if (!d[to[i]]&&val[i]) { d[to[i]]=d[u]+1; if (to[i]==T) return 1; q.push(to[i]); } } } return 0; } inline void add( int a, int b, int c) { to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } int main() { int i,j,k,l,x,y,z,a,b,c; scanf ( "%d" ,&n); S=0,T=tot=1; for (i=1;i<=n;i++) for (j=1;j<=n;j++) { scanf ( "%s" ,str+1); for (k=1;k<=n;k++) { if (str[k]== 'P' ) map[i][j][k]=1; if (str[k]== 'N' ) map[i][j][k]=0; if (str[k]== '?' ) map[i][j][k]=++tot; } } memset (head,-1, sizeof (head)); for (i=1;i<=n;i++) for (j=1;j<=n;j++) for (k=1;k<=n;k++) { if (map[i][j][k]>1) { a=b=0,c=map[i][j][k]; for (l=0;l<6;l++) { x=i+dx[l],y=j+dy[l],z=k+dz[l]; if (x&&y&&z&&x<=n&&y<=n&&z<=n) { if (map[x][y][z]==0) b++; if (map[x][y][z]==1) a++; if (map[x][y][z]>1&&((i^j^k)&1)) add(c,map[x][y][z],1),add(map[x][y][z],c,1),ans++; } } if ((i^j^k)&1) swap(a,b); add(S,c,a),add(c,T,b),ans+=a+b; } if (map[i][j][k]==0) { for (l=0;l<6;l++) { x=i+dx[l],y=j+dy[l],z=k+dz[l]; if (x&&y&&z&&x<=n&&y<=n&&z<=n&&map[x][y][z]==1) ans++; } } } while (bfs()) ans-=dfs(S,1<<30); printf ( "%d" ,ans); return 0; } |
| 欢迎来原网站坐坐! >原文链接<
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步