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

版权声明:是自己手打的没错 https://blog.csdn.net/Mr_Treeeee/article/details/82630587

https://nanti.jisuanke.com/t/30994

题意:

每个作业都有a和b,第i次做这个作业得到的分数为i*a+b。每个作业还可能会有前置作业。

问你最大分数是多少。可以不做。

POINT:

20个作业,可以状压。时间就是这个状态1的个数。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL long long
const int N = 20;
const LL inf = 0x3f3f3f3f3f3f3f3f;
int a[N],b[N],pre[N];
LL dp[1<<N];
int tm[1<<N];

int main()
{
	tm[0]=0;
	for(int i=1;i<(1<<N);i++){
		tm[i]=1+tm[i-(i&-i)];
	}
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d%d",&a[i],&b[i]);
		int s;scanf("%d",&s);
		for(int j=1;j<=s;j++){
			int to;scanf("%d",&to);
			to--;
			pre[i]|=1<<to;
		}
	}
	for(int i=1;i<(1<<n);i++) dp[i]=-inf;
	dp[0]=0;
	LL ans=0;
	for(int i=0;i<(1<<n);i++){
		if(dp[i]==-inf) continue;
		for(int j=0;j<n;j++){
			if((i&(1<<j))==0&&(i&pre[j])==pre[j]){
				int to=i|(1<<j);
				dp[to]=max(dp[to],dp[i]+1LL*(tm[i]+1)*a[j]+b[j]);
				ans=max(ans,dp[to]);
			}
		}
	}
	printf("%lld\n",ans);
	return 0;

}

猜你喜欢

转载自blog.csdn.net/Mr_Treeeee/article/details/82630587