BZOJ4057 [Cerc2012]Kingdoms
阿新 • • 發佈:2018-11-27
題意
有一些王國陷入了一系列的經濟危機。在很多年以前,他們私底下互相借了許多錢。現在,隨著他們的負債被揭發,王國的崩潰不可避免地發生了……現在有n個王國,對於每對王國A和B,A欠B的錢被記為d_AB(我們假設有d_BA=-d_AB成立)。如果一個王國入不敷出(即需要支付超過所能獲得的錢),它就可能破產。每當一個王國破產,與它相關的所有債務關係都會被去除,無論是正是負。而王國們的破產不是一瞬間完成的,而是第一個王國破產後,接下來可能破產的王國再繼續破產,直到剩下的王國經濟都是穩定的。不同的結局將取決於誰先破產,尤其是有的結局只會留下一個王國。請你計算,對於每個王國,是否存在一種結局使得該王國是唯一的倖存者。
\(n \leq 20\)
分析
一看到n=20,考慮狀壓dp。
用0/1揹包\(f(s)\)表示能否以集合\(s\)中的王國作為倖存者。
轉移就列舉每個點是否會破產,然後把破產後的狀態賦為1即可。
時間複雜度\(O(T \cdot 2^n \cdot n^2)\),上限很鬆。
程式碼
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<set> #include<map> #include<queue> #include<bitset> #include<stack> #include<algorithm> #include<cstring> #define rg register #define il inline #define co const template<class T>il T read() { rg T data=0; rg int w=1; rg char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) { data=data*10+ch-'0'; ch=getchar(); } return data*w; } template<class T>T read(T&x) { return x=read<T>(); } using namespace std; typedef long long ll; co int MAXN=20; int n,d[MAXN][MAXN]; bitset <1<<MAXN> ok; void init() { read(n); for(int i=0;i<(1<<n);++i) ok[i]=0; for(int i=0;i<n;++i) for(int j=0;j<n;++j) read(d[i][j]); } int tmp[MAXN],tcnt; int ban[MAXN],bcnt; void work() { ok[(1<<n)-1]=1; for(int i=(1<<n)-1;i>=0;--i) if(ok[i]) { tcnt=bcnt=0; for(int j=0;j<n;++j) if(i&(1<<j)) tmp[tcnt++]=j; for(int x=0;x<tcnt;++x) { int sum=0; for(int y=0;y<tcnt;++y) sum+=d[tmp[x]][tmp[y]]; if(sum>0) ban[bcnt++]=tmp[x]; } for(int j=0;j<bcnt;++j) ok[i-(1<<ban[j])]=1; } tcnt=0; for(int i=0;i<n;++i) if(ok[1<<i]) tmp[tcnt++]=i; if(tcnt>0) { for(int i=0;i<tcnt;++i) printf("%d ",tmp[i]+1); puts(""); } else puts("0"); } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); int T=read<int>(); while(T--) { init(); work(); } return 0; }