ACM-ICPC 2018 南京赛区网络预赛:E :AC Challenge题解

原题链接:AC Challenge

解析:题目要求求出最大分数,一共最多只有20题,故最多只有2^20种不同的状态,本题可以求出每一种状态的得分,取最高分即为答案(注:若最高分为负,则答案为0,对应题目中太简单而离开)

注意细节:

  • 有的题目前置条件可能是先完成它自己(故此题无法做)
  • 有的题目互为前置条件,形成一个环,故这些题都无法完成
  • 必须先完成该题的前置题才能做这题

实现步骤:

  1. 用ac[ i ]结构体来存放第 i 题的信息
  2. 定义数组dp[ ]来存放每种状态的信息(或许这就是dp吧)
  3. 用20位二进制位来表示状态,该位为1表示已做过该题,为0则表示未做该题,如此便可用递推来求状态,复杂度为O(n*2^n)

代码实例:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct Node{
	long long a,b;
	vector<int> pre;
	bool flag(int k){//用来判断前置条件是否满足,即是否可以做这题 
		for(int i = 0;i < pre.size();i++){
			if(((1<<(pre[i]-1))&k) == 0)	return false;
		}
		return true;
	}
	
}ac[25];
long long dp[1<<21];//一共最多2^20种状态 
int main()
{
	int n;
	scanf("%d",&n);
	long long  a,b;
	int s,pre;
	for(int i = 1;i <= n;i++){
		scanf("%lld%lld%d",&a,&b,&s);
		ac[i].a = a;
		ac[i].b = b;
		for(int j = 0;j < s;j++){
			scanf("%d",&pre);
			(ac[i].pre).push_back(pre);	
		}
	}
	//for(int i = 1;i <= n;i++)	cout << (ac[i].pre).size()<<endl;
	dp[0] = 0;
	for(int i = 1;i <= (1<<n);i++)	dp[i] = -100000000000;
	long long ans = 0;
	for(int i = 0; i < (1<<n);i++){
		long long t = 1;
		for(int j = 0;j < n;j++)
			if((1<<j)&i)	t++;//已经做出来几题,也就是已经用了几分钟
		for(int j = 1;j <= n;j++)
			if(ac[j].flag(i) && (((1<<(j-1))&i) == 0))//当第j题可以做,并且j题没有被做过时 
			dp[i|(1<<(j-1))] = max(dp[i|(1<<(j-1))],dp[i] + t*ac[j].a + ac[j].b); 
	}
	for(int i = 0;i < (1<<n);i++)
		ans = max(ans,dp[i]);
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/long98/p/10352182.html