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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

文理分科 (最小割问题)

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

Description

文理分科是一件很糾結的事情!(雖然看到這個題目的人肯定都沒有糾結過)
小P所在的班級要進行文理分科。他的班級可以用一個n*m的矩陣進行描述,每個格子代表一個同學的座位。每位同學必須從文科和理科中選擇一科。同學們在選擇科目的時候會獲得一個滿意值。滿意值按如下的方式得到:
1.如果第i行第秒J的同學選擇了文科,則他將獲得art[i][j]的滿意值,如果選擇理科,將得到science[i][j]的滿意值。
2.如果第i行第J列的同學選擇了文科,并且他相鄰(兩個格子相鄰當且僅當它們擁有一條相同的邊)的同學全部選擇了文科,則他會更開心,所以會增加same_art[i][j]的滿意值。
3.如果第i行第j列的同學選擇了理科,并且他相鄰的同學全部選擇了理科,則增加same_science[i]j[]的滿意值。小P想知道,大家應該如何選擇,才能使所有人的滿意值之和最大。
請告訴他這個最大值。

Input
第一行為兩個正整數:n,m
接下來n術m個整數,表示art[i][j];
接下來n術m個整數.表示science[i][j];
接下來n術m個整數,表示same_art[i][j];

Output
輸出為一個整數,表示最大的滿意值之和

Sample Input
3 4
13 2 4 13
7 13 8 12
18 17 0 5
8 13 15 4
11 3 8 11
11 18 6 5
1 2 3 4
4 2 3 2
3 1 0 4
3 2 3 2
0 2 2 1
0 2 4 4
Sample Output
152

Hint
樣例說明
1表示選擇文科,0表示選擇理科,方案如下:
1 0 0 1
0 1 0 0
1 0 0 0
N,M<=100,讀入數據均<=500

solution

非常經典的最小割問題

要么選理科,要么選文科

設計兩個超級點SSS表示選文科,TTT表示選理科

SSS分在一起的則選的是文科得到artartart,否則是理科得到sciencesciencescience

考慮怎么判斷可額外增加的滿意值

不妨再新添點與SSS連流量same_art的邊

怎么保證選了新添點,綁在一起的人都一起選文科呢??

直接與綁在一起的上下左右中點都連流量infinfinf,則一定不會出現在最小割里面

新添點與TTT連流量same_science的邊

怎么保證選了新添點,綁在一起的人都一起選理科呢??

同樣的,直接與綁在一起的上下左右中點都連流量infinfinf

則一定不會出現在最小割里面

最后就在這個圖內跑最大流,所有的滿意值減去最小割就是真正的最大滿意值

code

#include <queue> #include <cstdio> #include <cstring> using namespace std; #define maxn 200005 #define inf 0x7f7f7f7f struct node {int nxt, to, flow; }edge[maxn << 1]; queue < int > q; int n, m, cnt = 1, num; int dep[maxn], head[maxn], cur[maxn]; int dx[4] = { 1, -1, 0, 0 }, dy[4] = { 0, 0, 1, -1 };int id( int x, int y ) {return ( x - 1 ) * m + y; }bool inside( int x, int y ) {if( x < 1 || x > n || y < 1 || y > m ) return 0;else return 1; }void addEdge( int u, int v, int w ) {cnt ++;edge[cnt].nxt = head[u];edge[cnt].to = v;edge[cnt].flow = w;head[u] = cnt;cnt ++;edge[cnt].nxt = head[v];edge[cnt].to = u;edge[cnt].flow = 0;head[v] = cnt; }int bfs( int s, int t ) {memcpy( cur, head, sizeof( head ) );memset( dep, 0, sizeof( dep ) );dep[s] = 1;q.push( s );while( ! q.empty() ) {int u = q.front(); q.pop();for( int i = head[u];i;i = edge[i].nxt ) {int v = edge[i].to;if( ! dep[v] && edge[i].flow ) {dep[v] = dep[u] + 1;q.push( v );}}}return dep[t]; }int dfs( int u, int t, int cap ) {if( ! cap || u == t ) return cap;int flow = 0;for( int i = cur[u];i;i = edge[i].nxt ) {cur[u] = i;int v = edge[i].to;if( dep[v] == dep[u] + 1 ) {int w = dfs( v, t, min( cap, edge[i].flow ) );if( ! w ) continue;flow += w;cap -= w;edge[i].flow -= w;edge[i ^ 1].flow += w;if( ! cap ) break;}}return flow; }int dinic( int s, int t ) {int ans = 0;while( bfs( s, t ) )ans += dfs( s, t, inf );return ans; }int main() {scanf( "%d %d", &n, &m );int ans = 0, S = 0, T = n * m + 1, w; num = n * m + 1;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ ) {scanf( "%d", &w );addEdge( S, id( i, j ), w );ans += w;}for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ ) {scanf( "%d", &w );addEdge( id( i, j ), T, w );ans += w;}for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ ) {scanf( "%d", &w );ans += w;num ++;addEdge( S, num, w );addEdge( num, id( i, j ), inf );for( int k = 0;k < 4;k ++ )if( inside( i + dx[k], j + dy[k] ) )addEdge( num, id( i + dx[k], j + dy[k] ), inf );}for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ ) {scanf( "%d", &w );ans += w;num ++;addEdge( num, T, w );addEdge( id( i, j ), num, inf );for( int k = 0;k < 4;k ++ )if( inside( i + dx[k], j + dy[k] ) )addEdge( id( i + dx[k], j + dy[k] ), num, inf );}printf( "%d\n", ans - dinic( S, T ) );return 0; }

總結

以上是生活随笔為你收集整理的文理分科 (最小割问题)的全部內容,希望文章能夠幫你解決所遇到的問題。

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