網絡流_洛谷P2472

題目:
題目背景
07四川省選

題目描述
在一個r行c列的網格地圖中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任務是讓儘量多的蜥蜴逃到邊界外。

每行每列中相鄰石柱的距離爲1,蜥蜴的跳躍距離是d,即蜥蜴可以跳到平面距離不超過d的任何一個石柱上。石柱都不穩定,每次當蜥蜴跳躍時,所離開的石柱高度減1(如果仍然落在地圖內部,則到達的石柱高度不變),如果該石柱原來高度爲1,則蜥蜴離開後消失。以後其他蜥蜴不能落腳。任何時刻不能有兩隻蜥蜴在同一個石柱上。

輸入格式
輸入第一行爲三個整數r,c,d,即地圖的規模與最大跳躍距離。以下r行爲石柱的初始狀態,0表示沒有石柱,1~3表示石柱的初始高度。以下r行爲蜥蜴位置,“L”表示蜥蜴,“.”表示沒有蜥蜴。

輸出格式
輸出僅一行,包含一個整數,即無法逃離的蜥蜴總數的最小值。

輸入輸出樣例
輸入 #1 複製
5 8 2
00000000
02000000
00321100
02000000
00000000


…LLLL…


輸出 #1 複製
1
說明/提示
100%的數據滿足:1<=r, c<=20, 1<=d<=4

解題思路:
構圖:首先構建一個s, t(源點,匯點);讓所有可以跳躍的石柱裂點,一個入點,一個出點。然後讓源點指向所有蜥蜴所在的石柱的入點,邊權都爲1;讓所有石柱的入點指向出點,邊權爲各自的數字;然後讓可以跳躍的石柱的出點指向各自可以跳躍的石柱的入點,最後將所有可以跳躍並且可以跳出邊界的石柱的出點指向匯點,且邊權都爲inf。最後跑一遍最大流。(inf = 0x3f3f3f3f)

注意點:
1.注意原始輸入的2個矩陣中間都沒有空格, 全都是字符;
2.題目中跳躍的距離指的是平面距離,是可以直接用數學公式算的;
3.跳躍的判斷條件 if(i + ncu_d > n || i - ncu_d < 1 || j + ncu_d > m || j - ncu_d < 1) add(u, t, inf);
4.題目中要我們輸出的是最少的不能逃脫的蜥蜴的個數,所以最後的答案 = 蜥蜴數 - maxflow;
5.記得在計算蜥蜴數的時候,假如設ans 表示蜥蜴數,要記得給ans 初始化爲0。

AC代碼:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

typedef pair<int, int> PII;

const int N = 4000, M = 4e5;
const int inf = 0x3f3f3f3f;

int n, m, ncu_d, s, t, maxflow;
int h[N], w[M], e[M], ne[M], idx;
int g[N][N];
int d[N];
char tmp[N][N], tmp1[N][N];

inline void add(int a, int b, int c) {
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
	e[idx] = a, w[idx] = 0, ne[idx] = h[b], h[b] = idx ++;
}

inline bool bfs(void) {
	memset(d, 0, sizeof d);
	queue<int> q;
	
	while(q.size()) q.pop(); 
	d[s] = 1, q.push(s);
	
	while(q.size()) {
		int u = q.front(); q.pop();
		
		for(int i = h[u]; i != -1; i = ne[i]) {
			int v = e[i];
			if(w[i] && !d[v]) {
				q.push(v);
				d[v] = d[u] + 1;
			}
		}
	}
	
	if(d[t] == 0) return false;
	return true;
}

inline int dinic(int u, int flow) {
	if(u == t) return flow;
	
	for(int i = h[u]; i != -1; i = ne[i]) {
		int v = e[i];
		if(d[v] == d[u] + 1 && w[i]) {
			int k = dinic(v, min(flow, w[i]));
			if(k) {
				w[i] -= k;
				w[i ^ 1] += k;
				return k;
			} else d[v] = 0;
		}
	}
	
	return 0;
}

inline int get_sum(int a, int b, int c, int d) {
	return (a - c) * (a - c) + (b - d) * (b - d);
}

int main(void) {
//	freopen("in.txt", "r", stdin);
	
	scanf("%d%d%d", &n, &m, &ncu_d);
	memset(h, -1, sizeof h);
	s = n * m * 2 + 6, t = s + 1;
	
	//裂點 
	for(int i = 1; i <= n; i ++) scanf("%s", tmp1[i] + 1);
	getchar();
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= m; j ++) {
			g[i][j] = tmp1[i][j] - '0';
			if(g[i][j] > 0) {
				int u = (i - 1) * m + j;
				int v = n * m + (i - 1) * m + j;
				add(u, v, g[i][j]);
			}
		}
		
	//可以跳躍的點 
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= m; j ++) 
			if(g[i][j]) {
				
				int u = n * m + (i - 1) * m + j;
				
				for(int i1 = 1; i1 <= n; i1 ++) 
					for(int j1 = 1; j1 <= m; j1 ++) {
						if(i1 == i && j1 == j) continue;
						if(!g[i1][j1]) continue;
						if(ncu_d * ncu_d >= get_sum(i, j, i1, j1))
							add(u, (i1 - 1) * m + j1, inf);
					}
							
				//判斷是否能夠到達匯點 
				if(i + ncu_d > n  || i - ncu_d < 1 || j + ncu_d > m || j - ncu_d < 1) add(u, t, inf);
			}
	
	int ans = 0;	
	//源點連蜥蜴所在的柱子 
	for(int i = 1; i <= n; i ++) scanf("%s", tmp[i] + 1);
	for(int i = 1; i <= n; i ++)
		for(int j = 1; j <= m; j ++)
			if(tmp[i][j] == 'L') {
				int u = (i - 1) * m + j;
				add(s, u, 1);
				ans ++;
			}	
	
	//跑最大流
	int flow;
	while(bfs()) 
	while(flow = dinic(s, inf)) maxflow += flow;
	
	printf("%d\n", ans - maxflow);
	
//	fclose(stdin);
	return 0; 
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章