ACM-ICPC 2018 南京赛区网络预赛_E_ AC Challenge_(状压dp)

版权声明: https://blog.csdn.net/yyy_3y/article/details/82313990

传送门

题意:
1)n个题目,每个题目的权值为a i ,b i ,和s个先决条件(也就是说要先做出这几题才能做这道题),如果在T分钟做出来这题,收益就是a i *T+a i 问你能获得的最大收益。
思路:
1)一共就20题,很有状压的感觉。
2)主要思路就是对于当前的一个状态,如果当前这道题没有做过并且这道题的的先决条件都已做过,那么就更新,dp[i]就表示这个状态所能获得的最大收益。
3)优化方面的话,①可以预处理出每个状态有多少个1(也就是做过的题数)②对于每道题的先决条件用一个二进制存,比较的时候用 | 判断下就行。
4)复杂度是2 20 *20,不优化的话多一个20,4e8,听说也能过~(现场的时候4
e8并不敢写qwq,想到2e7才敢的qwq。)

#include<bits/stdc++.h>
#define debug(a) cout << #a << " " << a << endl
#define lnn putchar('\n')
#define see putchar(' ')
#define LL long long
#define ull unsigned long long
#define PI acos(-1.0)
#define eps 1e-6
const int N=2e5+7;
const LL inf=1e18;
using namespace std;
LL f[30],dp[1<<21],cnt[1<<21];
LL a[30],b[30];
void init()
{
    for(int i=0;i<(1<<21);i++){
        dp[i]=-inf;
        int tmp=i;
        int ans=0;
        while(tmp){
            if(tmp%2)ans++;
            tmp/=2;
        }
        cnt[i]=ans;
    }
}
int main ()
{
    //yyy_3y
    //freopen("1.in","r",stdin);
    init();
    int n; scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&a[i],&b[i]);
        int s; scanf("%d",&s);
        for(int j=1;j<=s;j++){
            LL x; scanf("%lld",&x);
            f[i]=(f[i]|(1<<(x-1)));
        }
    }
    dp[0]=0;
    for(int i=0;i<(1<<n);i++){
        for(int j=1;j<=n;j++){
            if( (i|f[j])>i ) continue;
            if((i>>(j-1))&1) continue;
            dp[i+(1<<(j-1))]=max(dp[i]+a[j]*(cnt[i]+1)+b[j],dp[i+(1<<(j-1))]);
        }
    }
    LL ans=0;
    for(int i=0;i<(1<<n);i++){
        ans=max(ans,dp[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yyy_3y/article/details/82313990
今日推荐