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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[Wf2011]Chips Challenge(最小费用最大流)

發(fā)布時(shí)間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Wf2011]Chips Challenge(最小费用最大流) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

[Wf2011]Chips Challenge

  • problem
  • solution
  • code

problem

BZOJ2673

solution

.

首先得知道這是網(wǎng)絡(luò)流,但真的看不出來啊!!我真的郁悶啊( ̄﹏ ̄;)

在知道做法是網(wǎng)絡(luò)流后,初讀題,肯定會(huì)想到將行列分左右點(diǎn),[1,n][1,n][1,n]表示行,[n+1,2n][n+1,2n][n+1,2n]表示列。

然后就發(fā)現(xiàn)舉步維艱,因?yàn)轭}目要維護(hù)的兩個(gè)條件都不是很好操作。

iiiiii 列零件數(shù)一樣,且每行零件數(shù)不能超過總數(shù)的 AB\frac{A}{B}BA?

這兩個(gè)限制條件都沒有明確具體零件個(gè)數(shù)要求,是隨著全局動(dòng)態(tài)變化的。

所以無法變成網(wǎng)絡(luò)流上的容量限制。

唯一知道的限制就是每行每列可放芯片的最大數(shù)量。

【可放指的是 . /C 的點(diǎn)】

注意到 nnn 的限制很小,不妨考慮枚舉每行可放零件的最大值個(gè)數(shù) MaxMaxMax

如果能通過網(wǎng)絡(luò)流求出總零件數(shù)量 tottottot,就可以逆向判斷 Max≤ABtot?Max?B≤A?totMax\le \frac{A}{B}tot\Rightarrow Max*B\le A*totMaxBA?tot?Max?BA?tot

而網(wǎng)絡(luò)流是最大流,是盡量做到流滿的,所以 tottottot 一定會(huì)盡可能的大。

增長同向平行,最大流就是在做盡量滿足判斷式子的過程。

所以如果最大流的結(jié)果還是不滿足上面的不等式,只能說明 MaxMaxMax 不是合法的。

自然地想到,對于可放芯片的位置 (i,j)(i,j)(i,j) 進(jìn)行 iii 行向 jjj 列連邊,容量為 111

這樣去跑網(wǎng)絡(luò)流,跑出的最大流確實(shí)是最多能放的芯片數(shù)量,但是這樣并沒有考慮到 iiiiii 列相等的限制。

因?yàn)椴荒苤赖?iii 行和第 iii 列具體放了多少個(gè)芯片,沒有明確的容量限制。

但是轉(zhuǎn)化一下,第 iii 行放了芯片的位置和第 iii 列沒放芯片的位置加起來一共是等于 nnn 的。

所以想到新建一個(gè)連接點(diǎn) kkk,分別讓行列點(diǎn)向 kkk 連邊。

行連接的邊流過的流量來表示行放芯片的個(gè)數(shù),列連接的邊流過的流量來表示列不放芯片的個(gè)數(shù)。

行列與 kkk 之間的邊容量設(shè)為 ∞∞

然后連接點(diǎn)向 ttt 連邊,容量為 nnn,保證 k→tk\rightarrow tkt 的邊滿流即可。

因?yàn)檫@樣代表著第 iii 行放的個(gè)數(shù)和第 iii 列不放的個(gè)數(shù)加在一起是等于 nnn 的,變相地滿足第 iii 行和第 iii 列個(gè)數(shù)相同的限制。

但是怎么能一些邊流了表示不選,一些邊流了表示要選。最大流上面看到了是不能做到的,那就只能考慮最小費(fèi)用了。

iii 流給連接點(diǎn) kkk 的表示要放的芯片,列 iii 流給 kkk 的表示不放的芯片,所以 i→ji\rightarrow jij 這種流給其它列點(diǎn)就應(yīng)當(dāng)表示 (i,j)(i,j)(i,j) 不放芯片,所以只有 iiijjj 列是 . 才有選擇不放的可能。

為了記錄這樣的邊流了多少,就把這種邊帶上費(fèi)用 111,跑最小費(fèi)用就是盡可能減少不放的,即最大化放的芯片。

除了這樣的邊,其余邊費(fèi)用就為 000,屬于要跑最大流。

別忘了,一開始枚舉的每行放芯片個(gè)數(shù)的限制,所以行與連接點(diǎn)之間的容量應(yīng)該修改為 MaxMaxMax

注意到,現(xiàn)在的網(wǎng)絡(luò)還有一個(gè)冗余的地方,列 iii 的出邊只有連接點(diǎn) kkk,且容量為 ∞∞,所以可以將列 iii 與連接點(diǎn)進(jìn)行合并。

那么現(xiàn)在的網(wǎng)絡(luò),行 iii 的流量只有兩種去向:經(jīng)過列 iii 最多流 MaxMaxMax 個(gè),剩下的都是流到其他列 jjj 地方,表示不放芯片,且?guī)в匈M(fèi)用 111

最后最大流減去最小費(fèi)用就是真正放的芯片個(gè)數(shù),再減去一定放的 C 個(gè)數(shù)就是新放的芯片個(gè)數(shù)。

最后記得還有行列分別與源匯的連邊。

通過 s→is\rightarrow isi 容量為第 iii 行可放的芯片數(shù)量來限制第 iii 行放置的個(gè)數(shù)。

通過 j→tj\rightarrow tjt 容量為第 jjj 列可放的芯片數(shù)量來限制第 jjj 列放置的個(gè)數(shù)。【準(zhǔn)確來說是 j+n→tj+n\rightarrow tj+nt,大家意會(huì)就行】

最后讓這個(gè)網(wǎng)絡(luò)滿流即可。

總結(jié)一下建圖過程:
{s→irowi,0i+n→ncoli,0i→j+n1,1(ch[i][j]=′.′)i→i+nMax,0\begin{cases}s\rightarrow i\quad \quad \quad row_i,0\\i+n\rightarrow n\quad col_i,0\\i\rightarrow j+n\quad 1,1\ (ch[i][j]='.')\\i\rightarrow i+n\quad Max,0\end{cases} ??????????sirowi?,0i+nncoli?,0ij+n1,1?(ch[i][j]=.)ii+nMax,0?

code

#include <bits/stdc++.h> using namespace std; #define maxn 105 #define maxm 5005 int n, a, b, s, t, cnt; bool vis[maxn]; char ch[maxn][maxn]; int dis[maxn], head[maxn], lst[maxn], row[maxn], col[maxn]; struct node { int to, nxt, flow, w; }E[maxm]; queue < int > q;void addedge( int u, int v, int flow, int w ) {E[cnt] = { v, head[u], flow, w };head[u] = cnt ++;E[cnt] = { u, head[v], 0, -w };head[v] = cnt ++; }bool spfa() {memset( dis, 0x7f, sizeof( dis ) );memset( lst, -1, sizeof( lst ) );dis[s] = 0; q.push( s );while( ! q.empty() ) {int u = q.front(); q.pop(); vis[u] = 0;for( int i = head[u];~ i;i = E[i].nxt ) {int v = E[i].to;if( dis[v] > dis[u] + E[i].w and E[i].flow ) {dis[v] = dis[u] + E[i].w;lst[v] = i;if( ! vis[v] ) vis[v] = 1, q.push( v );}}}return ~ lst[t]; }void MCMF( int &flow, int &cost ) {flow = cost = 0;while( spfa() ) {int Min = 1e9;for( int i = lst[t];~ i;i = lst[E[i ^ 1].to] )Min = min( Min, E[i].flow );for( int i = lst[t];~ i;i = lst[E[i ^ 1].to] )cost += E[i].w * Min, E[i].flow -= Min, E[i ^ 1].flow += Min;flow += Min;} }int main() {int Case = 0;while( ~ scanf( "%d %d %d", &n, &a, &b ) ) {if( ! n and ! a and ! b ) break;memset( row, 0, sizeof( row ) );memset( col, 0, sizeof( col ) );s = 0, t = n << 1 | 1;int sum = 0, used = 0;for( int i = 1;i <= n;i ++ ) {scanf( "%s", ch[i] + 1 );for( int j = 1;j <= n;j ++ )if( ch[i][j] != '/' ) {sum ++, row[i] ++, col[j] ++;used += ch[i][j] == 'C';}}int ans = -1;for( int Max = 0, flow, cost;Max <= n;Max ++ ) {memset( head, -1, sizeof( head ) ); cnt = 0;for( int i = 1;i <= n;i ++ ) {addedge( s, i, row[i], 0 );addedge( i + n, t, col[i], 0 );addedge( i, i + n, Max, 0 );for( int j = 1;j <= n;j ++ )if( ch[i][j] == '.' ) addedge( i, j + n, 1, 1 );}MCMF( flow, cost );if( flow == sum and Max * b <= ( sum - cost ) * a )ans = max( ans, sum - cost );}printf( "Case %d: ", ++ Case );if( ~ ans ) printf( "%d\n", ans - used );else printf( "impossible\n" );}return 0; }

總結(jié)

以上是生活随笔為你收集整理的[Wf2011]Chips Challenge(最小费用最大流)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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