题解:P5458 [BJOI2016] 水晶
每次听别人讲网络流,讲到这道题时都叫我们自行看题,看来这道题目确实是又臭又长。
首先,这道题目的多个坐标可能对应一个点,具体一点说,就是 \(x, y, z\) 坐标同时加上或减去一个数,它表示的还是同一个格子,因此我们将 \(x, y, z\) 坐标同时减去 \(z\),那么所有格子的 \(z\) 坐标就都是 \(0\) 了,此时我们就将这个 \(3\) 维坐标 \((x, y, z)\) 转化成了 \(2\) 维坐标 \((x - z, y - z)\),且此时一个坐标就对应一个格子。
其次我们考虑 \(3\) 个有水晶的格子,如果它们要形成共振,如果排列成三角形,那么这 \(3\) 个格子一定是 \((x, y)\),\((x, y - 1)\)(或 \((x - 1, y)\)),\((x - 1, y - 1)\),那它们的横纵坐标之和就是 \(x + y, x + y - 1, x + y - 2\),显而易见,它们构成了一个 \(\bmod \, 3\) 的剩余系;如果排列成直线形,那么这 \(3\) 个格子一定是 \((x, y)\),\((x, y - 1)\)(或 \((x - 1, y)\)),\((x, y + 1)\)(或 \((x + 1, y)\)),那它们的横纵坐标之和就是 \(x + y, x + y + 1, x + y - 1\),显而易见,它们也构成了一个 \(\bmod \, 3\) 的剩余系。这就说明,如果 \(3\) 个水晶相邻且横纵坐标之和 \(\bmod \, 3\) 分别是 \(0, 1, 2\),那么它们就会产生共振。
现在题目信息转化得差不多了,考虑到题目要求剩余价值最大,这不难想到最小割模型,而且由于权值在点上,这启示我们要拆点。我们将每个水晶拆成入点和出点,中间连一条容量为价值的边。我们再建立出源点和汇点,从源点向每个横纵坐标之和 \(\bmod \, 3 = 1\) 的水晶的入点连边,再从每个横纵坐标之和 \(\bmod \, 3 = 1\) 的水晶的出点向每个横纵坐标之和 \(\bmod \, 3 = 0\) 的水晶的入点连边,接着从每个横纵坐标之和 \(\bmod \, 3 = 1\) 的水晶的出点向每个横纵坐标之和 \(\bmod \, 3 = 2\) 的水晶的入点连边,最后再从每个横纵坐标之和 \(\bmod \, 3 = 2\) 的水晶的出点向汇点连边,边全都是 \(\infty\)。此时 \(3\) 个会产生共振的水晶就会构成一条路径,必须割掉一条边。此时跑一遍最大流就可以得出答案。
最后一点,就是一个点可能会有多个水晶,我们只需要从这些水晶中选一个出来,并从这个水晶的出点向其他水晶的出点连容量为 \(\infty\) 边即可,这样就可以将这两个水晶合并在一起了。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair <int, int>
#define mk make_pair
const int N = 1e5 + 9, M = 1e6 + 9, K = 6e3 + 9, INF = 1e18 + 9;
struct Edge{
int v, nex;
double c;
} e[M << 1];
int head[N], ecnt = 1;
void addEdge(int u, int v, double c){
e[++ecnt] = Edge{v, head[u], c};
head[u] = ecnt;
}
int cur[N], dep[N], n, m, s, t;
bool bfs();
double dfs(int u, double flow);
int x[N], y[N], z[N], tmp[N], tot, d[6][2] = {{-1, -1}, {0, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 0}};
double c[N], sum, ans;
map <pii, int> id;
signed main(){
scanf("%lld", &n);
s = n * 2 + 1, t = n * 2 + 2;
for(int i = 1; i <= n; i++){
scanf("%lld%lld%lld%lf", &x[i], &y[i], &z[i], &c[i]);
x[i] -= z[i], y[i] -= z[i];
if(((x[i] + y[i]) % 3 + 3) % 3 == 0)
c[i] += c[i] * 0.1;
sum += c[i];
if(id[mk(x[i], y[i])]){
addEdge(id[mk(x[i], y[i])] + n, i + n, INF);
addEdge(i + n, id[mk(x[i], y[i])] + n, 0);
} else
id[mk(x[i], y[i])] = i;
addEdge(i + n, i, c[i]);
addEdge(i, i + n, 0);
}
for(int i = 1; i <= n; i++){
if(((x[i] + y[i]) % 3 + 3) % 3 == 1){
addEdge(s, i + n, INF);
addEdge(i + n, s, 0);
} else if(((x[i] + y[i]) % 3 + 3) % 3 == 2){
addEdge(i, t, INF);
addEdge(t, i, 0);
}
}
for(int i = 1; i <= n; i++){
if(((x[i] + y[i]) % 3 + 3) % 3 == 1){
for(int j = 0; j < 6; j++){
int dx = x[i] + d[j][0];
int dy = y[i] + d[j][1];
if(id[mk(dx, dy)] && ((dx + dy) % 3 + 3) % 3 == 0){
addEdge(i, id[mk(dx, dy)] + n, INF);
addEdge(id[mk(dx, dy)] + n, i, 0);
}
}
}
if(((x[i] + y[i]) % 3 + 3) % 3 == 0){
for(int j = 0; j < 6; j++){
int dx = x[i] + d[j][0];
int dy = y[i] + d[j][1];
if(id[mk(dx, dy)] && ((dx + dy) % 3 + 3) % 3 == 2){
addEdge(i, id[mk(dx, dy)] + n, INF);
addEdge(id[mk(dx, dy)] + n, i, 0);
}
}
}
}
while(bfs())
ans += dfs(s, INF);
printf("%.1lf", sum - ans);
return 0;
}
本文来自博客园,作者:Orange_new,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18946654

浙公网安备 33010602011771号