[SCOI2007]蜥蜴 (网络最大流+拆点)
刚学习网络流
一上午熟悉\(Dinic\)板子+就调过了这一个题
题目描述
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。
输入格式
输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。
输出格式
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
样例
样例输入
5 8 2
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........
样例输出
1
数据范围与提示
100%的数据满足:1<=r, c<=20, 1<=d<=4
Solution
看上去就是每个点有限制能跳过几只蜥蜴
就相当于边权中的流量上限
考虑如何建图
由于对于单个点无法增加边权
选择拆点成边
拆出的点之间的边权就是流量的限制
首先建立超级源点\(s=0\)
因为图中有\(n*m\)个点
拆完之后\(2*n*m\)个点
所以超级汇点是\(t=2*n*m+1\)
图中建边有四种
- 由源点\(s\)出发,向所有蜥蜴所在的点建立边权为\(1\)的边
- 所有有高度(就是蜥蜴可以跳跃的点)拆点,向\((i,j)\)对应的点\((i,j) + n*m\)建边,边权为当前点的高度,即流量限制
- 由所有一次能够跳出矩阵的点向超级汇点\(t\)建边,边权无限制,为\(inf\)
- 矩阵内部互相能够到达的点,边权无限制,为\(inf\)
最后直接跑\(Dinic\)就行了
注意\(Dinic\)跑出来的是能够逃离的蜥蜴的数量
要用总数量减一下
拆出来的点,一个是原点,一个是新点
原点负责所有向外建边
新点负责其他点向自己建边
这个建图的时候要注意一下
上午调了好久~
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#define min(a, b) ({register int AA = a, BB = b; AA < BB ? AA : BB;})
#define inf 10000009
using namespace std;
inline int read(){
int x = 0, w = 1;
char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return x * w;
}
const int ss = 10010;
struct node{
int to, nxt, w;
}edge[ss * 20];
int head[ss], tot = 1;
inline void add(register int u, register int v, register int w){
edge[++tot].to = v;
edge[tot].nxt = head[u];
edge[tot].w = w;
head[u] = tot;
}
int dis[ss], cur[ss];
int r, c, d, s, t;
bool vis[ss];
queue<int> q;
inline bool spfa(register int s){
for(register int i = 0; i <= t; i++)
vis[i] = 0, dis[i] = 0x3f3f3f3f, cur[i] = head[i];
dis[s] = 0;
q.push(s);
while(!q.empty()){
register int u = q.front();
q.pop();
vis[u] = 0;
for(register int i = head[u]; i; i = edge[i].nxt){
register int v = edge[i].to;
if(dis[v] > dis[u] + 1 && edge[i].w){
dis[v] = dis[u] + 1;
if(!vis[v]) q.push(v), vis[v] = 1;
}
}
}
return dis[t] != 0x3f3f3f3f;
}
inline int dfs(register int u, register int flow){
register int res = 0;
if(u == t) return flow;
for(register int i = cur[u]; i; i = edge[i].nxt){
cur[u] = i;
register int v = edge[i].to;
if(dis[v] == dis[u] + 1 && edge[i].w){
if(res = dfs(v, min(flow, edge[i].w))){
edge[i].w -= res;
edge[i ^ 1].w += res;
return res;
}
}
}
return 0;
}
long long ans, cnt;
inline long long dinic(){
register long long minflow = 0;
while(spfa(s)){
while(minflow = dfs(s, 0x7fffffff))
ans += minflow;
}
return ans;
}
inline double getdis(register int a, register int b, register int c, register int d){
return sqrt((a - c) * (a - c) + (b - d) * (b - d));
}
inline int change(register int i, register int j){
return (i - 1) * c + j;
}
int a[25][25], flag[25][25];
char ch[25];
signed main(){
r = read(), c = read(), d = read();
for(register int i = 1; i <= r; i++){
scanf("%s", ch + 1);
for(register int j = 1; j <= c; j++)
a[i][j] = ch[j] - '0';
}
for(register int i = 1; i <= r; i++){
scanf("%s", ch + 1);
for(register int j = 1; j <= c; j++)
if(ch[j] == 'L') flag[i][j] = 1;
}
s = 0, t = 2 * c * r + 1;
for(register int i = 1; i <= r; i++)
for(register int j = 1; j <= c; j++)
if(flag[i][j] == 1){
cnt++;
add(s, change(i, j), 1);
add(change(i, j), s, 0);
}
for(register int i = 1; i <= r; i++)
for(register int j = 1; j <= c; j++)
if(a[i][j]){
add(change(i, j), change(i, j) + r * c, a[i][j]);
add(change(i, j) + r * c, change(i, j), 0);
}
for(register int i = 1; i <= r; i++)
for(register int j = 1; j <= c; j++){
if(i > d && i <= r - d && j > d && j <= c - d) continue;
if(a[i][j]){
add(change(i, j) + r * c, t, inf);
add(t, change(i, j) + r * c, 0);
}
}
for(register int i = 1; i <= r; i++){
for(register int j = 1; j <= c; j++){
for(register int p = 1; p <= r; p++){
for(register int q = 1; q <= c; q++){
if(i == p && j == q) continue;
if(getdis(i, j, p, q) <= (double)d && a[i][j] && a[p][q]){
add(change(i, j) + r * c, change(p, q), inf);
add(change(p, q), change(i, j) + r * c, 0);
}
}
}
}
}
printf("%lld\n", cnt - dinic());
return 0;
}