欢迎访问 My Luogu Space。
【题目大意】
有一栋 h ∗ n ∗ m h*n*m h∗n∗m 个单元的大楼。
现在每个单元必须需要向周围六个相邻单元(如果在大楼的某一侧则会少一些相邻单元)中的两个连接安全疏散通道,每两个单元之间连接通道的费用不一定相同。
询问连接的最小费用。如果无法连接请输出"No Answer!"。
【题解】
费用流跑二分图匹配
很直接就可以想到网络流,只不过建边需要一点想法。
考虑到是两个单元相互连接,我们可以将所有的单元进行黑白染色,然后源点连向黑色,白色连向汇点,流量都为 2 2 2,费用为 0 0 0,。于每组相邻单元一定是不同颜色,那么就从黑色连向白色,流量为 1 1 1,费用为题目所给的费用。
跑最小费用最大流的二分图即可,输出时用流量判断是否能够连接即可。
注意:染色时有小技巧。
【代码】
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000+10;
const int INF = 0x3f3f3f3f;
struct EDGE{int to, w, f;}e[MAXN*2];
int h, n, m, s, t=100000, ans, ctn;
int id[20][20][20], f[MAXN];
int ct=1, hed[MAXN], nex[MAXN*2], cur[MAXN*2], dis[MAXN];
void add(int a, int b, int w, int f){
e[++ct].to=b, e[ct].w= w, e[ct].f=f, nex[ct]=hed[a], hed[a]=ct;
e[++ct].to=a, e[ct].w=-w,e[ct].f=0, nex[ct]=hed[b], hed[b]=ct;
}
bool spfa(){
memset(dis, INF, sizeof dis);
queue<int> Q; Q.push(s);
dis[s] = 0;
while(!Q.empty()){
int x=Q.front(); Q.pop();
f[x] = 0;
for(int i=hed[x]; i; i=nex[i]){
if(e[i].f && dis[x]+e[i].w<dis[e[i].to]){
dis[e[i].to] = dis[x]+e[i].w;
if(!f[e[i].to])
f[e[i].to] = 1, Q.push(e[i].to);
}
}
}
return dis[t] != INF;
}
int dfs(int x, int flow){
if(x == t) return flow;
int sum = 0; f[x] = 1;
for(int i=cur[x]; i; i=nex[i]){
cur[x] = i;
if(!f[e[i].to] && e[i].f && dis[e[i].to]==dis[x]+e[i].w){
int p = dfs(e[i].to, min(flow-sum, e[i].f));
sum += p;
e[i].f -= p;
e[i^1].f += p;
ans += p*e[i].w;
if(sum == flow) break;
}
}
f[x] = 0;
return sum;
}
int zkw(){
int sum = 0;
while(spfa()){
memcpy(cur, hed, sizeof hed);
sum += dfs(s, INF);
}
return sum;
}
int main(){
scanf("%d%d%d", &h, &n, &m);
for(int i=0; i<h; ++i)
for(int j=0; j<n; ++j)
for(int k=0; k<m; ++k){
id[i][j][k] = ++ctn;
if((i+j+k)&1) add(s, id[i][j][k], 0, 2);
else add(id[i][j][k], t, 0, 2);
}
for(int t=1; t<=h*n*m; ++t){
int i, j, k, c1, c2, c3;
scanf("%d%d%d%d%d%d", &i, &j, &k, &c1, &c2, &c3);
if((i+j+k)&1){
if(id[i+1][j][k]) add(id[i][j][k], id[i+1][j][k], c3, 1);
if(id[i][j+1][k]) add(id[i][j][k], id[i][j+1][k], c1, 1);
if(id[i][j][k+1]) add(id[i][j][k], id[i][j][k+1], c2, 1);
}
else{
if(id[i+1][j][k]) add(id[i+1][j][k], id[i][j][k], c3, 1);
if(id[i][j+1][k]) add(id[i][j+1][k], id[i][j][k], c1, 1);
if(id[i][j][k+1]) add(id[i][j][k+1], id[i][j][k], c2, 1);
}
}
if(zkw() == h*n*m) printf("%d", ans);
else puts("No Answer!");
return 0;
}