B - A Funny Bipartite Graph
生活随笔
收集整理的這篇文章主要介紹了
B - A Funny Bipartite Graph
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
B - A Funny Bipartite Graph
題意:
一個二分圖,左右各有n個點,左邊第i個點有一個屬性mi,它在一個圖中的價值為midi,其中di為它在圖中的度數(特殊的,如果度數為0,則價值為0),求一個該二分圖的子圖使得右邊的每個點度數都不為0且總價值最小,輸出最小價值。如果無解輸出?1
有若干個限制條件(i,j)表示子圖中左邊的點i和j不能同時存在
保證:
原二分圖中左邊的每個點度數在[1,3]之間。
左邊的i點和右邊的j點連線當且僅當i ≤ j
n<=18
mi<=100
題解:
參考題解:
文章1
文章2
這個題的思路非常妙
首先根據數據范圍確定方法為狀壓dp
我們既要維護左側的點,也有維護右側的點,兩側都是n,我們都用二進制取枚舉,那么復雜度就是n * 22n,這樣肯定不行,要先辦法優化
注意題目中有說左側的i選右側的j,當且僅當i<=j,也就是說當我們考慮左側的第i個點時,左側的后n-i個還沒選,右側的前i個點必須全選(不然往后再也選不了),也就是說左側的后n-i位和右側的前i位都沒啥用,所有我們可以將左側的前i位和右側的后n-i位拼成一起,這樣2n就可以存下,復雜度就是O(n*2n)
這波操作就相當于計組里面將32 位整數乘除法,它把乘數和結果同時存在了一個 64 位整數上
妙哉妙哉
思路很難,代碼也很難。。代碼之后更新
代碼:
#include<bits/stdc++.h> #define ll long long using namespace std; const int inf = 0x3f3f3f3f; int dp[2][1<<18]; int val[20], ban[20]; vector<int> g[20]; char s[20]; int n; void init(){scanf("%d", &n);for(int i = 0; i < n; ++i) g[i].clear();for(int i = 0; i < n; ++i) {scanf("%s", s);for(int j = 0; j < n; ++j) if(s[j] == '1') g[i].push_back(j);}for(int i = 0; i < n; ++i) {scanf("%s", s); ban[i] = 0;for(int j = 0; j < i; ++j) if(s[j] == '1') ban[i] |= (1<<j);}for(int i = 0; i < n; ++i) scanf("%d", &val[i]); } int sol(){int cur = 0, nxt = 1;memset(dp, 0x3f, sizeof dp);dp[cur][0] = 0;for(int i = 0; i < n; ++i){for(int mask = 0; mask < (1<<n); ++mask){int lstate = mask&((1<<i)-1);int rstate = mask&((1<<n)-(1<<i));if(dp[cur][mask] == inf) continue;// don't choose iif(rstate>>i&1) dp[nxt][(mask)^(1<<i)] = min(dp[nxt][(mask)^(1<<i)], dp[cur][mask]);if(ban[i]&lstate) continue;//can't choose ifor(int t = 1; t < (1<<g[i].size()); ++t){int cost = 1;int ex = 0;for(int j = 0; j < g[i].size(); ++j){int v = g[i][j];if(t>>j&1) cost *= val[i], ex |= 1<<v;}int nstate = rstate|ex;if( !(nstate>>i&1) ) continue;int sumstate=lstate|nstate;dp[nxt][sumstate] = min(dp[nxt][sumstate], dp[cur][mask] + cost);}}swap(cur, nxt);memset(dp[nxt], 0x3f, sizeof dp[nxt]);}int ans = inf;for(int i = 0; i < (1<<n); ++i) ans = min(ans, dp[cur][i]);if(ans == inf) return -1;return ans; } int main() {int T;cin>>T;while(T--){init();cout<<sol()<<endl;} } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的B - A Funny Bipartite Graph的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Bochs调试Linux内核初级入门2、
- 下一篇: Codeforces Round #71