ACM-ICPC 2018 南京赛区网络预赛:E :AC Challenge题解
原题链接:AC Challenge
解析:题目要求求出最大分数,一共最多只有20题,故最多只有2^20种不同的状态,本题可以求出每一种状态的得分,取最高分即为答案(注:若最高分为负,则答案为0,对应题目中太简单而离开)
注意细节:
- 有的题目前置条件可能是先完成它自己(故此题无法做)
- 有的题目互为前置条件,形成一个环,故这些题都无法完成
- 必须先完成该题的前置题才能做这题
实现步骤:
- 用ac[ i ]结构体来存放第 i 题的信息
- 定义数组dp[ ]来存放每种状态的信息(或许这就是dp吧)
- 用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\n",ans);
return 0;
}