ACM-ICPC 2018 南京赛区网络预赛 : E. AC Challenge(状压DP)

题目链接:https://nanti.jisuanke.com/t/30994


 

这道题出的很棒,是状压DP的入门题目,简单说一下题意

每道题会有前置的做题需求,给我们题目的价值表示方法,要我们求出做这些题目可以获得的做大价值。

由于最多只有20题,直接状压一下然后暴力就可以了。dp[i]表示状态为i时的最大价值


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
typedef unsigned int ui;
#define INF 0x3f3f3f3f
#define PB push_back
#define PI 3.1415926
#define SF scanf
#define PF printf
#define mem(a,x) memset(a,x,sizeof(a))
int gcd(int p, int q) {return q==0?p:gcd(q,p%q);}

const int maxn = 25;

struct node{
	int a, b, c;
}s[maxn];

LL dp[1<<22];
int cnt[1<<22];

void init(){
	for(int i = 0; i < 1<<(21); i++){
		int n = i, s;
		for(s = 0; n; ++s){
			n &= (n-1);
		}
		cnt[i] = s;
	} 
}

int main(){
	int n;
	init();
//	for(int i = 0; i <= 5; i++){
//		cout << cnt[i] << endl;
//	}
	while(scanf("%d", &n) != EOF){
		mem(s, 0);
		mem(dp, -INF);
		dp[0] = 0;
		for(int i = 1; i <= n; i++){
			int ss, p;
			scanf("%d%d%d", &s[i].a, &s[i].b, &ss);
			int sp = 0;
			while(ss--){
				scanf("%d", &p);
				sp = sp | (1 << (p - 1));
			}
			s[i].c = sp;
		}
		LL ans = 0;
		for(int i = 1; i < (1<<(n+1)); ++i){
			for(int j = 1; j <= n; ++j){
				if(i & (1<<(j-1))){
					LL tmp = i^(1<<(j-1));
					if((tmp&s[j].c) == s[j].c){
						dp[i] = max(dp[i], dp[tmp] + cnt[i]*s[j].a + s[j].b);
					}
				}
				ans = max(ans, dp[i]);
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
} 

/*
5
5 6 0
4 5 1 1
3 4 1 2
2 3 1 3
1 2 1 4
1
-100 0 0

55
0
*/

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值