1. 程式人生 > >BZOJ4057 [Cerc2012]Kingdoms

BZOJ4057 [Cerc2012]Kingdoms

題意

有一些王國陷入了一系列的經濟危機。在很多年以前,他們私底下互相借了許多錢。現在,隨著他們的負債被揭發,王國的崩潰不可避免地發生了……現在有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;
}