1. 程式人生 > >ACM-ICPC 2018 南京賽區網路預賽

ACM-ICPC 2018 南京賽區網路預賽

題意:

每個作業都有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;

}