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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

一般图带权多重匹配(欧拉图+最小费用流)

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一般图带权多重匹配(欧拉图+最小费用流) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

problem

給定 nnn 個數 {ai}\{a_i\}{ai?},其中 kkkaia_iai? 是奇數,再給一個 n×nn\times nn×n 的矩陣 {ci,j}\{c_{i,j}\}{ci,j?},無論是 aaa 還是 ccc,都保證是非負整數。

現在可以做一類操作:將 ai?1,aj?1a_i-1,a_j-1ai??1,aj??1,花費 ci,jc_{i,j}ci,j? 代價,i,ji,ji,j 可以相同。

要求把所有的 {ai}\{a_i\}{ai?} 全都變為 000。

求最小花費,無解輸出 ?1-1?1。

n≤50,k≤8n\le 50,k\le 8n50,k8,保證 ci,j=cj,ic_{i,j}=c_{j,i}ci,j?=cj,i?

solution

顯然,每次操作都會使得 (∑ai)?2(\sum a_i)-2(ai?)?2。所以如果 ∑ai\sum a_iai? 是奇數,即 aia_iai? 為奇數的 iii 有奇數個,則無解。

接下來再來解決有解的問題。

先考慮 k=0k=0k=0 的弱化版。

那就存在歐拉回路,要求每個點的入度和出度相同,經典網絡流模型轉化。

將每個點拆成兩個點,各放左右部,與源/匯點的連邊流量設置為 ai2\frac{a_i}22ai??。

花費針對“關系”而言,左右部點之間連邊流量無窮帶花費。

直接跑最小費用流即可。

轉化思考:

如果操作 i,ji,ji,j,就在圖上連一條 (i,j)(i,j)(i,j) 的邊。那么最后這張圖可能有重邊和若干個環。

發現這是一張歐拉圖,存在歐拉回路。我們能找到一種定向方式使得每個點的入度和出度相同。

推出存在一種最優方案使得每個點的入度和出度相同。

將每個點拆成入度點和出度點,轉化成匹配問題。

現在有幾個特殊點是奇數,歐拉回路不存在,變成存在歐拉路徑。

我們先通過若干次操作將這些奇數全都消成偶數,就又轉化成了歐拉回路,就可以套用上面的方法。

轉化思考:

我們通過對圖上進行加邊,使得這張圖最后仍是存在歐拉回路的圖。

由此推出存在一種最優方案使得奇數點的入度和出度只相差 111。

由于 kkk 非常小,我們大可直接狀壓枚舉哪一半的奇數點是入度多 111,剩下的就肯定是出度多 111

還是轉化成了入度和出度二分圖的匹配問題,仍然跑個最小費用流。

最后求個 min?\minmin 就完了。

code

#include <bits/stdc++.h> using namespace std; #define maxn 200 #define inf 0x7f7f7f7f struct node { int to, nxt, flow, cost; }E[maxn * maxn]; int head[maxn], dis[maxn], lst[maxn], a[maxn], b[maxn], id[maxn]; int c[maxn][maxn]; bool vis[maxn]; int n, cnt, m, s, t; queue < int > q;void addedge( int u, int v, int flow, int cost ) {E[++ cnt] = { v, head[u], flow, cost }, head[u] = cnt;E[++ cnt] = { u, head[v], 0, - cost }, head[v] = cnt; }bool SPFA() {memset( lst, -1, sizeof( lst ) );memset( dis, 0x7f, sizeof( dis ) );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].cost and E[i].flow ) {dis[v] = dis[u] + E[i].cost; lst[v] = i;if( ! vis[v] ) vis[v] = 1, q.push( v );}}}return ~ lst[t]; }int solve() {memset( head, -1, sizeof( head ) ), cnt = -1;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )addedge( i, j + n, inf, c[i][j] );for( int i = 1;i <= n;i ++ ) {addedge( s, i, a[i] + b[i] >> 1, 0 );addedge( i + n, t, a[i] - b[i] >> 1, 0 );}int ans = 0;while( SPFA() ) {int flow = inf;for( int i = lst[t];~ i;i = lst[E[i ^ 1].to] )flow = min( flow, E[i].flow );ans += flow * dis[t];for( int i = lst[t];~ i;i = lst[E[i ^ 1].to] ) {E[i ^ 1].flow += flow;E[i].flow -= flow;}}return ans; }int main() {scanf( "%d", &n ); s = 0, t = n << 1 | 1;for( int i = 1;i <= n;i ++ ) {scanf( "%d", &a[i] );if( a[i] & 1 ) id[m ++] = i;}for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )scanf( "%d", &c[i][j] );if( m & 1 ) return ! puts("-1");int ans = inf;for( int i = 0;i < (1 << m);i ++ ) {for( int j = 0;j < m;j ++ )if( i >> j & 1 ) b[id[j]] = 1;else b[id[j]] = -1;if( __builtin_popcount( i ) ^ (m >> 1) ) continue;ans = min( ans, solve() );}printf( "%d\n", ans );return 0; }

總結

以上是生活随笔為你收集整理的一般图带权多重匹配(欧拉图+最小费用流)的全部內容,希望文章能夠幫你解決所遇到的問題。

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