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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz467796454/article/details/82498995

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

样例输入1 
5
5 6 0
4 5 1 1
3 4 1 2
2 3 1 3
1 2 1 4
样例输出1 
55
样例输入2 
1
-100 0 0
样例输出2 
0

题意:n个题目,做每一个题目的得分是t*ai+bi,做某一题前必须先做完规定的题,求最大的得分

思路:n只有20,状压dp,dp[i]表示,i这个状态下的最大得分

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<set>
using namespace std;
typedef long long ll;

struct node{
	ll a,b;
	int s;
	int p[50];
}q[50];
ll dp[1<<20];//第i个状态的最大得分 

int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld%d",&q[i].a,&q[i].b,&q[i].s);
		for(int j=1;j<=q[i].s;j++){
			scanf("%d",&q[i].p[j]);
		}
	}
	memset(dp,0,sizeof(dp));
	for(int i=0;i<(1<<n);i++){//枚举每个状态 
		int flag=1;
		for(int j=1;j<=n;j++){
			if(!((1<<(j-1))&i))continue;//i这个状态下,j这一题没有做
			for(int k=1;k<=q[j].s;k++){//判断做j题前必做的题是否做了 
				if(!((1<<(q[j].p[k]-1))&i)){
					flag=0;break;
				}
			} 
			if(!flag)break;
		}
		if(!flag)continue;//存在某一已做的题,做这一题前的必做的题还没有做,说明这个状态不存在 
		int x=i;
		int t=0;//1的个数,即这个状态已经做了几题 
		while(x){
			if(x&1)t++;
			x>>=1;
		}
		for(int j=1;j<=n;j++){
			if(!((1<<(j-1))&i))continue;
			dp[i]=max(dp[i],dp[(1<<(j-1))^i]+t*q[j].a+q[j].b);//j这个问题在t这个时间做
			// (1<<(j-1))^i表示在i这个状态中,去掉j这个题的状态 
		}
	}
	printf("%lld\n",dp[(1<<n)-1]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yz467796454/article/details/82498995