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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

[Wf2011]Chips Challenge

  • problem
  • solution
  • code

problem

BZOJ2673

solution

.

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

在知道做法是網絡流后,初讀題,肯定會想到將行列分左右點,[1,n][1,n][1,n]表示行,[n+1,2n][n+1,2n][n+1,2n]表示列。

然后就發現舉步維艱,因為題目要維護的兩個條件都不是很好操作。

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

這兩個限制條件都沒有明確具體零件個數要求,是隨著全局動態變化的。

所以無法變成網絡流上的容量限制。

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

【可放指的是 . /C 的點】

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

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

而網絡流是最大流,是盡量做到流滿的,所以 tottottot 一定會盡可能的大。

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

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

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

這樣去跑網絡流,跑出的最大流確實是最多能放的芯片數量,但是這樣并沒有考慮到 iiiiii 列相等的限制。

因為不能知道第 iii 行和第 iii 列具體放了多少個芯片,沒有明確的容量限制。

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

所以想到新建一個連接點 kkk,分別讓行列點向 kkk 連邊。

行連接的邊流過的流量來表示行放芯片的個數,列連接的邊流過的流量來表示列不放芯片的個數。

行列與 kkk 之間的邊容量設為 ∞∞

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

因為這樣代表著第 iii 行放的個數和第 iii 列不放的個數加在一起是等于 nnn 的,變相地滿足第 iii 行和第 iii 列個數相同的限制。

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

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

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

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

別忘了,一開始枚舉的每行放芯片個數的限制,所以行與連接點之間的容量應該修改為 MaxMaxMax

注意到,現在的網絡還有一個冗余的地方,列 iii 的出邊只有連接點 kkk,且容量為 ∞∞,所以可以將列 iii 與連接點進行合并。

那么現在的網絡,行 iii 的流量只有兩種去向:經過列 iii 最多流 MaxMaxMax 個,剩下的都是流到其他列 jjj 地方,表示不放芯片,且帶有費用 111

最后最大流減去最小費用就是真正放的芯片個數,再減去一定放的 C 個數就是新放的芯片個數。

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

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

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

最后讓這個網絡滿流即可。

總結一下建圖過程:
{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; }

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。