给出一个
假设所有相邻的方块之间全部都产生能量,且不考虑已经上好色的方块,之后减去不合法的就行了。
一般来说这种相邻的方块之间会产生一些什么的一般都是把所有点染色,一种颜色的与S相连,另一种与T相连。这道题中,左侧的点若是最终属于S集,代表这个点上了P色,否则上了N色;右侧的点若是最终属于T集,代表这个点上了P色,否则上了N色。在最后的答案中,我们只记录P色周围有多少N色,而不讨论N色周围有多少P色。
因为现在我们假设的是所有的块之间都产生能量,所以先从S到所有左侧的点连上流量为这个点周围相邻的点的个数,右侧的点同理。如果一个点并不是P色,那么它就要失去所有的能量(因为只记录P色产生的能量)。
如果左边的点和右边的点不在同一个集合的话(也就是它们之间的边被割开了),那么他们最后的颜色就是相同的,因此不会产生能量,左侧和右侧各减1,所以这个边的流量就是2。
之后跑个Dinic就行了。。。
#define _CRT_SECURE_NO_WARNINGS
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 50
#define MAXP (MAX * MAX * MAX)
#define MAXE 1000010
#define INF 0x3f3f3f3f
#define S 0
#define T (MAXP - 1)
using namespace std;
#define INRANGE(x, y, z) (x * y * z && x <= m && y <= m && z <= m)
const int dx[] = {0, 1, -1, 0, 0, 0, 0};
const int dy[] = {0, 0, 0, 1, -1, 0, 0};
const int dz[] = {0, 0, 0, 0, 0, 1, -1};
struct MaxFlow{
int head[MAXP], total;
int next[MAXE], aim[MAXE], flow[MAXE];
int deep[MAXP];
MaxFlow():total(1) {}
void Add(int x, int y, int f) {
next[++total] = head[x];
aim[total] = y;
flow[total] = f;
head[x] = total;
}
void Insert(int x, int y, int f) {
Add(x, y, f);
Add(y, x, 0);
}
bool BFS() {
static queue<int> q;
while(!q.empty()) q.pop();
memset(deep, 0, sizeof(deep));
deep[S] = 1;
q.push(S);
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = head[x]; i; i = next[i])
if(flow[i] && !deep[aim[i]]) {
deep[aim[i]] = deep[x] + 1;
q.push(aim[i]);
if(aim[i] == T) return true;
}
}
return false;
}
int Dinic(int x, int f) {
if(x == T) return f;
int temp = f;
for(int i = head[x]; i; i = next[i])
if(flow[i] && deep[aim[i]] == deep[x] + 1 && temp) {
int away = Dinic(aim[i], min(flow[i], temp));
if(!away) deep[aim[i]] = 0;
flow[i] -= away;
flow[i^1] += away;
temp -= away;
}
return f - temp;
}
}solver;
int m;
char src[MAX][MAX][MAX];
int num[MAX][MAX][MAX], cnt;
int ans;
int main()
{
cin >> m;
for(int i = 1; i <= m; ++i)
for(int j = 1; j <= m; ++j)
scanf("%s", src[i][j] + 1);
for(int i = 1; i <= m; ++i)
for(int j = 1; j <= m; ++j)
for(int k = 1; k <= m; ++k)
num[i][j][k] = ++cnt;
for(int i = 1; i <= m; ++i)
for(int j = 1; j <= m; ++j)
for(int k = 1; k <= m; ++k) {
int near = 0;
for(int d = 1; d <= 6; ++d) {
int fx = i + dx[d];
int fy = j + dy[d];
int fz = k + dz[d];
bool flag = INRANGE(fx, fy, fz);
near += flag;
if(flag && (i + j + k)&1)
solver.Insert(num[i][j][k], num[fx][fy][fz], 2);
}
ans += near;
if((i + j + k)&1)
solver.Insert(S, num[i][j][k], near);
else
solver.Insert(num[i][j][k], T, near);
}
for(int i = 1; i <= m; ++i)
for(int j = 1; j <= m; ++j)
for(int k = 1; k <= m; ++k)
if((i + j + k)&1) {
if(src[i][j][k] == ‘P‘)
solver.Insert(S, num[i][j][k], INF);
else if(src[i][j][k] == ‘N‘)
solver.Insert(num[i][j][k], T, INF);
}
else {
if(src[i][j][k] == ‘P‘)
solver.Insert(num[i][j][k], T, INF);
else if(src[i][j][k] == ‘N‘)
solver.Insert(S, num[i][j][k], INF);
}
int max_flow = 0;
while(solver.BFS())
max_flow += solver.Dinic(S, INF);
cout << ans - max_flow << endl;
return 0;
}
BZOJ 1976 BeiJing2010组队 能量魔方 Cube 最小割
原文地址:http://blog.csdn.net/jiangyuze831/article/details/44920957