bzoj 4057: [Cerc2012]Kingdoms 状压dp

本文介绍了一种算法,用于模拟多个王国之间的经济关系及其潜在的破产连锁反应。通过状态转移的方式,确定哪些王国能够在一系列经济危机中幸存下来。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

有一些王国陷入了一系列的经济危机。在很多年以前,他们私底下互相借了许多钱。现在,随着他们的负债被揭发,王国的崩溃不可避免地发生了……现在有n个王国,对于每对王国A和B,A欠B的钱被记为d_AB(我们假设有d_BA=-d_AB成立)。如果一个王国入不敷出(即需要支付超过所能获得的钱),它就可能破产。每当一个王国破产,与它相关的所有债务关系都会被去除,无论是正是负。而王国们的破产不是一瞬间完成的,而是第一个王国破产后,接下来可能破产的王国再继续破产,直到剩下的王国经济都是稳定的。不同的结局将取决于谁先破产,尤其是有的结局只会留下一个王国。请你计算,对于每个王国,是否存在一种结局使得该王国是唯一的幸存者。

Input

第一行一个正整数T,表示有T组数据。

每组数据第一行一个正整数n,表示有n个王国,1 <= n <= 20。
接下来n行,每行n个整数,第i行第j个整数表示d_ij,保证有d_ii = 0, d_ij = -d_ji, |d_ij| <= 10^6。

Output

每组数据输出一行,按照升序输出所有可能的王国编号,空格隔开,如果没有一个王国能满足条件,输出一个0。


         这道题尽量不要使用memset哦,多组数据会跪的。

        首先我们考虑状态的定义,用state中的1或0表示这个公司是否存活,dp[state]表示这个状态是否可以到达,最后要求的便是每个只有一个1的状态是否能够到达。

        接着考虑转移我们可以枚举先今存活的公司,统计他当前的债务情况,如果可以破产,那么就让它破产的状态为真,每次对可达到的状态进行以上操作即可。

        接着考虑边界条件,由于最开始所有公司正常,所以将全1状态定义为真即可。

        最后答案便是每个只有一个1的状态是否能够到达,要注意的是没有答案输出0(WA了100发)

       下附AC代码。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 21
using namespace std;
int n;
int val[maxn][maxn];
bool dp[(1<<20)];
int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        scanf("%d",&n);
        
        for(int state=0;state<(1<<n);state++)
        dp[state]=0;
        
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        scanf("%d",&val[i][j]);
        memset(dp,0,sizeof(dp));
        dp[(1<<n)-1]=1;
        for(int state=((1<<n)-1);state>=0;state--)
        if(dp[state])
        {
            for(int i=0;i<n;i++)
            if(((1<<i)&state))
            {
                int cal=0;
                for(int j=0;j<n;j++)
                if(((1<<j)&state))
                {
                    cal+=val[i][j];
                }
                if(cal>0)
                {
                    dp[(state-(1<<i))]=1;
                }
            }
        }
        int flag=0;
        for(int i=0;i<n;i++)
        {
        	if(dp[(1<<i)])
        	{
        		if(flag)
        		printf(" ");
        		
				printf("%d",i+1);
				
        		flag=1;           	 	
        	}
		}
		if(flag)
        printf("\n");
        else
        printf("0\n");
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值