zoukankan      html  css  js  c++  java
  • JDOJ 1098: 夏娜的菠萝包

    JDOJ 1098: 夏娜的菠萝包

    JDOJ传送门

    Description

    问题描述:夏娜很喜欢吃菠萝包,她的经纪人RC每半个月就要为她安排接下来的菠萝包计划。今天是7月份,RC又要去商场进货买菠萝包了。这次RC总共买了N种菠萝包,每种一个。每个菠萝包都有一个初始美味值Ti,每过一天就会减少Di,即第2天美味值为Ti-Di,第3天为Ti-2*Di,依此类推。一旦美味值减为负数,那个包就坏掉了,不能吃了。 RC每天都要为夏娜安排当天吃菠萝包的组合,这些组合不是随意的,而是只能从夏娜喜欢的M种搭配中挑选一种。每种搭配是由Ki个菠萝包组成的,一种搭配的总美味值是这Ki个菠萝包当天的美味值之和再加上一个额外的搭配美味值Ei。不过要注意,一旦某种搭配的其中一个菠萝包坏掉了,这个搭配就不能选用了。而且,有可能存在两个搭配,里面的组合是一样的,但额外的搭配美味值却不同。 RC想让可爱的夏娜尽可能地吃得美味,因此希望能找出一种最优的方案,让小夏娜吃上若干天的菠萝包,这些天的美味值之和最大。但RC面临着两个邪恶的敌人,一个叫bug,一个叫zzy,他们也想抢夺这个经纪人之位,因此要是他们提出更优的方案,RC就可能会失去他的夏娜了。那么,你们能帮帮这个可怜的RC吗?

    Input

    输入格式:输入文件包含多组数据。每组数据的第一行为一个正整数N(N<=14),表示菠萝包的种数,按1-N编号。接下来N行,每行两个正整数Ti(Ti<100)和Di(Di<100),表示第i种菠萝包的初始美味值和每天递减值。第N+2行为一个正整数M,表示搭配的种数。接下来M(M<=20)行,每行先是一个正整数Ki,表示组成这个搭配的菠萝包数目,然后是一个非负整数Ei(Ei<100),表示这种搭配额外的美味值,最后是Ki个整数,每个整数为菠萝包的编号。当N=0时表示输入结束。

    Output

    输出格式:对于每组输入数据输出一行,仅包含一个整数,表示最大的美味值之和。

    Sample Input

    输入样例: 2 3 1 4 2 2 1 1 1 1 1 2 2 3 1 4 2 3 1 1 1 1 1 2 2 2 1 2 0

    Sample Output

    输出样例: 8 9

    HINT

    样例说明: 对于第一个样例,只有两个方案: 1、 第一天选择搭配1,即吃编号1的菠萝包,美味值为3+1=4;第二天选择搭配2,即吃编号为2的菠萝包,美味值为2+1=3。此时已把菠萝包都吃完了,总和为4+3=7. 2、 第一天选择搭配2,即吃编号为2的菠萝包,美味值为4+1=5;第二天选择搭配1,即吃编号1的菠萝包,美味值为2+1=3,此时已把菠萝包都吃完了,总和为5+3=8。因此,第2个方案为最优方案,最大美味值总和为8. 对于第二个样例,除了上述两个方案,还有第三个: 3、 第一天选择搭配3,即编号为1和2的菠萝包一起吃,美味值为3+4+2=9。此时已经把菠萝包都吃完了,总和即为9. 虽然第3个方案只能吃1天,但因为其总和最大,所以选择第3个方案,答案为9。


    最优解声明:

    (拿小号刷的,逃)
    (懂的都懂)

    题解:

    直觉设状态(dp[i][S])表示第i天吃掉状态为S的菠萝包的最大美味值。这个要靠磨才能磨出来。怎么磨?膜QYB呗。

    于是考虑转移。这个转移一定是跟方案有关的。首先因为每个菠萝包只有一个,所以当前状态和新加入状态不能有重合。否则的话就不能转移。这个用and运算来判就好。如果A&B=0,说明两个状态没有重合。

    但是题目细节比较多。每个状态在每个时刻的美味值还不一样。这个就需要大力预处理了。

    (per[i][S])表示第i天选择S方案的美味值。这个S是01串,表示一种方案。

    想要处理出这个,就需要(t[i][j])表示第i天吃j号包的美味值。

    然后就可以了。

    但是挂了20分,至今不知道为啥。等抓到虫了就补更。

    先放80pts代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,m,k[21],e[21],id[15],ans;
    int t[15][15],d[15];//t[i][j]表示第i天吃j号菠萝包的美味值
    int per[15][1<<15];//per[i][j]表示第i天吃方案j的美味值,j为01串
    bool flag;
    int dp[15][1<<15];//dp[i][S]表示吃到第i天已经吃了S状态的美味值之和。
    int sta[22],cnt;//存储每个m的状态
    void clear()
    {
        memset(t,-1,sizeof(t));
        memset(d,0,sizeof(d));
        memset(per,0,sizeof(per));
        memset(sta,0,sizeof(sta));
        memset(k,0,sizeof(k));
        memset(e,0,sizeof(e));
        memset(id,0,sizeof(id));
        memset(dp,0,sizeof(dp));
        cnt=0;
        ans=-1;
    }
    int main()
    {
        while(scanf("%d",&n)&&n)
        {
            clear();
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d",&t[1][i],&d[i]);
                for(int j=2;t[1][i]-(j-1)*d[i]>=0 && j<=n;j++)
                    t[j][i]=t[1][i]-(j-1)*d[i];
            }
            scanf("%d",&m);
            for(int i=1;i<=m;i++)
            {
                int tmp=0;
                scanf("%d%d",&k[i],&e[i]);
                for(int j=1;j<=k[i];j++)
                {
                    scanf("%d",&id[j]);
                    tmp|=1<<(id[j]-1);
                }//处理出tmp表示当前搭配的01串
                if(per[0][tmp]&&per[0][tmp]<e[i])
                {
                    for(int j=1;per[j][tmp]>0;j++)
                        per[j][tmp]=(per[j][tmp]-per[0][tmp]+e[i]);
                    per[0][tmp]=e[i];
                    continue;
                }//如果之前出现过比现在的e值小的方案,就更新
                else if(per[0][tmp]&&per[0][tmp]>=e[i])
                    continue;
                //如果之前出现过比现在e值大的方案,这个方案就无效
                per[0][tmp]=e[i];//如果这是一个全新方案
                sta[++cnt]=tmp;
                flag=0;
                for(int j=1;j<=n;j++)
                {
                    int temp=0;
                    for(int l=1;l<=k[i];l++)
                    {
                        if(t[j][id[l]]<0)//当前天数已经有菠萝包变质,当前方案即不合法
                        {
                            per[j][tmp]=-1;
                            flag=1;
                            break;
                        }
                        temp+=t[j][id[l]];
                    }
                    if(flag)
                    {
                        per[j][tmp]=-1;
                        continue;
                    }
                    else
                        per[j][tmp]=(temp+e[i]);
                }
            }//预处理部分结束
            for(int i=1;i<=n;i++)
                for(int j=0;j<(1<<n);j++)
                    for(int l=1;l<=cnt;l++)
                        if((!(j&sta[l]))&&per[i][sta[l]]!=-1)
                            dp[i][j|sta[l]]=max(dp[i-1][j]+per[i][sta[l]],dp[i][j|sta[l]]);
            //状压及其转移
            for(int i=1;i<=n;i++)
                for(int j=0;j<(1<<n);j++)
                    ans=max(ans,dp[i][j]);
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    常见http状态码
    通过adb shell命令查看内存,CPU,启动时间,电量等信息
    Jmeter获取数据库数据参数化
    jmeter链接mysql数据库,sql数据库,oracle数据库
    appium 隐藏键盘
    python编码
    python:打印所有文件名字的扩展名
    python中字符串常见操作
    python中的字符串存储及切片介绍
    Ubuntu14.04安装部署bugzilla5.0.3
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13803330.html
Copyright © 2011-2022 走看看