日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

[codevs 1789] 最大获利(2006年NOI全国竞赛)

發(fā)布時(shí)間:2025/3/15 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [codevs 1789] 最大获利(2006年NOI全国竞赛) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

描述:

http://codevs.cn/problem/1789/


題解:

第一次寫(xiě)最大閉合子圖的題,把過(guò)程寫(xiě)詳細(xì)。

如果要選擇第i個(gè)用戶(hù)群,那么就必須選擇中轉(zhuǎn)站ai和bi。而這個(gè)約束條件是最大閉合子圖的經(jīng)典條件,先來(lái)看看最大閉合子圖的定義:

最大權(quán)閉合子圖即為,給定一個(gè)圖,每個(gè)點(diǎn)有一個(gè)權(quán)值,有正有負(fù)。有一些有向邊(i,j),表示若選了點(diǎn)i,那么也必須選點(diǎn)j。請(qǐng)求出一個(gè)合法點(diǎn)集使得點(diǎn)權(quán)和盡量大.

然后開(kāi)始建模:
首先建立二分圖,建立附加源s和附加匯t,從s到每個(gè)用戶(hù)群連一條容量為ci的邊,表示選擇這個(gè)用戶(hù)群的收益;從每個(gè)中轉(zhuǎn)站到t連一條容量為pi的邊,表示中轉(zhuǎn)站的成本,注意這個(gè)成本其實(shí)是負(fù)數(shù),這里取相反數(shù)即正值,后面要轉(zhuǎn)化。再?gòu)挠脩?hù)群到需要的中轉(zhuǎn)站連一條容量為INF的邊。求s到t的最大流,用戶(hù)群的權(quán)值和-最大流量就是最終結(jié)果。

分析:
最大流一定對(duì)應(yīng)一個(gè)最小割,那么考慮這樣一組邊:s->ci->ai、bi->t,其中有且只有一條邊在最小割中【1】,且只能為s->ai(bi)和ci->t中的一條【2】,因?yàn)樽钚「畹男再|(zhì)得出【1】,而用戶(hù)群和中轉(zhuǎn)站之間的邊容量已經(jīng)被設(shè)為INF,不會(huì)滿(mǎn)流得出【2】。

假設(shè)所有用戶(hù)群都選擇并且不需要任何中轉(zhuǎn)站,此時(shí)獲利為T(mén)otal。然后我們讓割集的流量代表相對(duì)Total損失的錢(qián)。損失的錢(qián)包括兩部分:1.放棄選擇的用戶(hù)群所帶來(lái)的收益;2.選擇一些必要的中轉(zhuǎn)站需要的成本。

  • 如果s->ci在最小割中,代表?yè)p失掉ci的錢(qián),那么就沒(méi)有選擇ci這個(gè)中轉(zhuǎn)站。對(duì)相應(yīng)ai和bi沒(méi)有影響。
  • 相反的,如果s->ci不在最小割中,則代表選擇ci這個(gè)中轉(zhuǎn)站(因?yàn)椴粨p失ci的獲利),那么相應(yīng)ai、bi->t的邊一定在最小割中,代表選擇ai和bi(損失這些成本)。這樣就滿(mǎn)足了選擇ci,ai、bi一定被選。
  • 最后要讓損失的錢(qián)最少,也就是割的流量最小,最小割流量對(duì)應(yīng)著最大流MaxFlow,那么

    ans=Total?MaxFlow;


    代碼:

    454ms 12MB

    #include<cstdio> #include<cstring> #include<vector> #include<queue> using namespace std;const int maxn = 5000 + 10; const int maxnode = 50000 + 5000 + 10; const int INF = 1e9 + 7;struct Edge {int from, to, cap, flow; };struct ISAP {int n, m, s, t;vector<Edge> edges;vector<int> G[maxnode]; bool vis[maxnode]; int d[maxnode], cur[maxnode], p[maxnode], num[maxnode]; void AddEdge(int from, int to, int cap) {edges.push_back((Edge){from, to, cap, 0});edges.push_back((Edge){to, from, 0, 0});m = edges.size();G[from].push_back(m-2);G[to].push_back(m-1);}bool BFS() {memset(vis, 0, sizeof(vis));queue<int> Q;Q.push(t);vis[t] = 1;d[t] = 0;while(!Q.empty()) {int x = Q.front(); Q.pop();for(int i = 0; i < G[x].size(); i++) {Edge& e = edges[G[x][i]^1];if(!vis[e.from] && e.cap > e.flow) {vis[e.from] = 1;d[e.from] = d[x] + 1;Q.push(e.from);}}}return vis[s];}int Augment() {int x = t, a = INF;while(x != s) {Edge& e = edges[p[x]];a = min(a, e.cap-e.flow);x = edges[p[x]].from;}x = t;while(x != s) {edges[p[x]].flow += a;edges[p[x]^1].flow -= a;x = edges[p[x]].from;}return a;}int Maxflow(int s, int t, int n) {this->s = s; this->t = t; this->n = n;int flow = 0;BFS();memset(num, 0, sizeof(num));for(int i = 0; i < n; i++) num[d[i]]++;int x = s;memset(cur, 0, sizeof(cur));while(d[s] < n) {if(x == t) {flow += Augment();x = s;}int ok = 0;for(int i = cur[x]; i < G[x].size(); i++) {Edge& e = edges[G[x][i]];if(e.cap > e.flow && d[x] == d[e.to] + 1) { ok = 1;p[e.to] = G[x][i];cur[x] = i;x = e.to;break;}}if(!ok) { int m = n-1;for(int i = 0; i < G[x].size(); i++) {Edge& e = edges[G[x][i]];if(e.cap > e.flow) m = min(m, d[e.to]);}if(--num[d[x]] == 0) break;num[d[x] = m+1]++;cur[x] = 0; if(x != s) x = edges[p[x]].from;}}return flow;} }isap;int p[maxn];int main() {int n, m, s, t;scanf("%d%d", &n, &m);s = 0; t = m + n + 1;for(int i = m + 1; i <= m + n; i++) {int p;scanf("%d", &p);isap.AddEdge(i, t, p);}int tot = 0;for(int i = 1; i <= m; i++) {int a, b, c;scanf("%d%d%d", &a, &b, &c);tot += c; isap.AddEdge(s, i, c);isap.AddEdge(i, a + m, INF);isap.AddEdge(i, b + m, INF);}printf("%d\n", tot - isap.Maxflow(s, t, t+1));return 0; }

    總結(jié)

    以上是生活随笔為你收集整理的[codevs 1789] 最大获利(2006年NOI全国竞赛)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。