[BZOJ 2127] happiness 【最小割】

來源:互聯網
上載者:User

標籤:

題目連結:BZOJ - 2127

 

題目分析

首先,每個人要麼學文科,要麼學理科,所以可以想到是一個最小割模型。

我們就確定一個人如果和 S 相連就是學文,如果和 T 相連就是學理。

那麼我們再來確定建圖。首先使用最小割,就是先加上所有可能獲得的權值,再減去最小割(即不能獲得的權值)。

如果一個人學理,就要割掉與 S 相連的邊,那麼就是要割掉學文的收益。於是,對於每個點,從 S 向它連邊,權值為它學文的收益。

同理,對於每個點,從它向 T 連邊,權值為它學理的收益。

對於兩個相鄰的人,他們有同時學文的收益和同時學理的收益。

如果他們都學文,就會失去同時學理的收益,於是從他們分別向 T 連邊,權值為他們同時學理收益的一半。

同理,從 S 向他們分別連邊,權值為他們同時學文收益的一半。

但是如果一個人學文一個人學理,就要失去同時學文和同時學理的收益,因此,在他們之前連雙向邊,權值為同時學文的收益加同時學理的收益的一半。

這樣建圖,就巧妙地實現了控制不同的收益。

由於建圖的時候權值的一半可能不是整數,先將權值乘 2 ,最後再除以 2 。

 

代碼
#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;const int MaxN = 100 + 5, MaxNode = 10000 + 15, INF = 999999999;int n, m, Sum, S, T, Tot, MaxFlow;int Idx[MaxN][MaxN], Wk[MaxN][MaxN][5], Lk[MaxN][MaxN][5], Num[MaxNode], d[MaxNode];struct Edge{int v, w;Edge *Next, *Other;} E[MaxNode * 12], *P = E, *Point[MaxNode], *Last[MaxNode];inline void AddEdge(int x, int y, int z){Edge *Q = ++P; ++P; P -> v = y; P -> w = z;P -> Next = Point[x]; Point[x] = P; P -> Other = Q;Q -> v = x; Q -> w = 0;Q -> Next = Point[y]; Point[y] = Q; Q -> Other = P;}inline int gmin(int a, int b) {return a < b ? a : b;}int DFS(int Now, int Flow) {if (Now == T) return Flow;int ret = 0;for (Edge *j = Last[Now]; j; j = j -> Next)if (j -> w && d[Now] == d[j -> v] + 1){Last[Now] = j;int p = DFS(j -> v, gmin(j -> w, Flow - ret));ret += p; j -> w -= p; j -> Other -> w += p;if (ret == Flow) return ret;}if (d[S] >= Tot) return ret;if (--Num[d[Now]] == 0) d[S] = Tot;++Num[++d[Now]];Last[Now] = Point[Now];return ret;}int main(){scanf("%d%d", &n, &m);for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)Idx[i][j] = (i - 1) * m + j;S = n * m + 1; T = n * m + 2; Tot = T;for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)scanf("%d", &Wk[i][j][0]);for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)scanf("%d", &Lk[i][j][0]);for (int i = 1; i <= n - 1; ++i)for (int j = 1; j <= m; ++j)scanf("%d", &Wk[i][j][1]);for (int i = 1; i <= n - 1; ++i)for (int j = 1; j <= m; ++j)scanf("%d", &Lk[i][j][1]);for (int i = 1; i <= n; ++i)for (int j = 1; j <= m - 1; ++j)scanf("%d", &Wk[i][j][2]);for (int i = 1; i <= n; ++i)for (int j = 1; j <= m - 1; ++j)scanf("%d", &Lk[i][j][2]);int v1, v2, v3;for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j){Sum += Wk[i][j][0] + Wk[i][j][1] + Wk[i][j][2];Sum += Lk[i][j][0] + Lk[i][j][1] + Lk[i][j][2];v1 = Wk[i][j][0] * 2 + Wk[i][j][1] + Wk[i][j][2]; v2 = Lk[i][j][0] * 2 + Lk[i][j][1] + Lk[i][j][2];v1 += Wk[i - 1][j][1]; v2 += Lk[i - 1][j][1];v1 += Wk[i][j - 1][2]; v2 += Lk[i][j - 1][2];AddEdge(S, Idx[i][j], v1);AddEdge(Idx[i][j], T, v2);if (i < n){v3 = Wk[i][j][1] + Lk[i][j][1];AddEdge(Idx[i][j], Idx[i + 1][j], v3);AddEdge(Idx[i + 1][j], Idx[i][j], v3);}if (j < m){v3 = Wk[i][j][2] + Lk[i][j][2];AddEdge(Idx[i][j], Idx[i][j + 1], v3);AddEdge(Idx[i][j + 1], Idx[i][j], v3);}}MaxFlow = 0;memset(d, 0, sizeof(d));memset(Num, 0, sizeof(Num)); Num[0] = Tot;for (int i = 1; i <= Tot; ++i) Last[i] = Point[i];while (d[S] < Tot) MaxFlow += DFS(S, INF);Sum -= MaxFlow >> 1;printf("%d\n", Sum);return 0;}

  

[BZOJ 2127] happiness 【最小割】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.