HDU-1569 方格取数(2) 最小割最大流
生活随笔
收集整理的這篇文章主要介紹了
HDU-1569 方格取数(2) 最小割最大流
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題義很簡單,還記得方格取數(1)的時候,使用狀態壓縮寫的,這里由于行列數太大,因此無法進行壓縮。所以要運用的最小割最大流的思想來解這道題。
大概是這樣分析的,題義是要我們求在一個方格內取出N個點,使得這N個獨立的(不相鄰)點集的和最大。我們可以將問題轉化為最小割來求解。首先,我們將方格進行黑白相間的染色,然后再將任意一種顏色(黑色)作為源點,一種顏色(白色)作為匯點。我們的算法過程就是一個不斷尋找增廣路的過程。當我們找到最大流的時,也就是此時不存在從黑色到白色的路徑,也即不存在不相鄰的兩個方格能夠連通了。而此時的最大流就是分割兩個區間的最小割,拿總合值減去這個最小割就是我們想要得到的結果?! ?/p>
代碼如下:
#include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #define RE(x) (x)^1 #define INF 0x3fffffff #define MAXN 50 using namespace std;int N, M, dis[MAXN*MAXN+10], head[MAXN*MAXN+10], idx, source, sink; int G[MAXN+10][MAXN+10];int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};struct Edge {int v, cap, next; }e[200000];void init() {idx = -1;source = N*M, sink = N*M+1;memset(head, 0xff, sizeof (head)); }int to(int x, int y) {return (x-1)*M+y-1; }void insert(int a, int b, int c) {++idx;e[idx].v = b, e[idx].cap = c;e[idx].next = head[a], head[a] = idx; }bool judge(int x, int y) {if (x < 1 || x > N || y < 1 || y > M) {return false;}else {return true;} }bool bfs() {int u;queue<int>q;memset(dis, 0xff, sizeof (dis));dis[source] = 0;q.push(source);while (!q.empty()) {u = q.front();q.pop();for (int i = head[u]; i != -1; i = e[i].next) {if (dis[e[i].v] == -1 && e[i].cap > 0) {dis[e[i].v] = dis[u] + 1;q.push(e[i].v);}}}return dis[sink] != -1; }int dfs(int u, int flow) {if (u == sink) {return flow;}int tf = 0, sf;for (int i = head[u]; i != -1; i = e[i].next) {if (dis[u]+1 == dis[e[i].v] && e[i].cap > 0 && (sf = dfs(e[i].v, min(flow-tf, e[i].cap)))) {e[i].cap -= sf, e[RE(i)].cap += sf;tf += sf;if (tf == flow) {return flow;}}}if (!tf) {dis[u] = -1;}return tf; }int Dinic() {int ans = 0;while (bfs()) {ans += dfs(source, INF);}return ans; }int main() {int sum;while (scanf("%d %d", &N, &M) == 2) {sum = 0;init();for (int i = 1; i <= N; ++i) {for (int j = 1; j <= M; ++j) {scanf("%d", &G[i][j]);sum += G[i][j];}}for (int i = 1; i <= N; ++i) {for (int j = 1; j <= M; ++j) {if (!((i+j)&1)) { insert(source, to(i, j), G[i][j]);insert(to(i, j), source, 0);for (int k = 0; k < 4; ++k) {int xx = i+dir[k][0], yy = j+dir[k][1]; if (judge(xx, yy)) {insert(to(i, j), to(xx, yy), G[i][j]);insert(to(xx, yy), to(i, j), 0);}}} else {insert(to(i, j), sink, G[i][j]);insert(sink, to(i, j), 0);}}}printf("%d\n", sum - Dinic());}return 0; }轉載于:https://www.cnblogs.com/Lyush/archive/2012/07/06/2578869.html
總結
以上是生活随笔為你收集整理的HDU-1569 方格取数(2) 最小割最大流的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql导入sql文件
- 下一篇: 流水号结合自定义函数实现申请业务