AC Challenge
题目链接: AC Challenge
题意
给出N个任务,每个任务花费一个单位时间,现在求每个任务完成时,会获得 a[i]∗t+b[i] a [ i ] ∗ t + b [ i ] 的价值,但是每个任务都有必须要在之前完成的任务,就是前置任务。
数据范围: N<20,−109<a[i],b[i]<109 N < 20 , − 10 9 < a [ i ] , b [ i ] < 10 9
思路
这题非常容易想歪,因为有前置条件,所以易想到网络流,然而,这个时间非常难弄,所以我们从另一点出发,就是20这个数据,一看就是状压的标准形态嘛,所以,我们选择状压。
状压要开两个主要的数组, dp[1<<20],cnt[1<<20] d p [ 1 << 20 ] , c n t [ 1 << 20 ] .分别储存的是当前状态的最大值,当前状态所能达到的时间。
让后三个循环
for i:1->n //代表的是几次
for j:0->n //代表的是第几件物品
for k:0->(1<<n)-1 //所有状态
判断能否到达,判断是否达成前置条件,判断是否计算过
进行DP选择
代码
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef double db;
typedef long long ll;
const int MAXN = (int)40+7;
const int INF = (int)0x3f3f3f3f;
int a[MAXN];
int b[MAXN];
int pre[1<<21];
ll dp[1<<21];
int cnt[1<<21];
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n;
cin >> n;
rep(i,0,n-1) {
cin >> a[i] >> b[i];
int cnt;
cin >> cnt;
rep(j,1,cnt) {
int tmp;
cin >> tmp;
pre[i] |= 1<<(tmp-1);
}
}
ll res = 0;
rep(i,1,n) {
rep(j,0,n-1) {
rep(k,0,(1<<n)-1){
if (cnt[k] != i-1 || ((k>>(j))&1) == 1 || (k&pre[j])!=pre[j]) continue;
if (dp[k|1<<j] < dp[k] + 1LL*a[j]*i + b[j]) {
cnt[k|1<<j] = cnt[k] + 1;
dp[k|1<<j] = dp[k] + 1LL*a[j]*i + b[j];
}
}
}
}
res = max_element(dp,dp+(1<<20))-dp;
cout << dp[res] << endl;
}