1. 程式人生 > 實用技巧 >【GDOI2007】JZOJ2020年8月10日提高組T1 夏娜的菠蘿包

【GDOI2007】JZOJ2020年8月10日提高組T1 夏娜的菠蘿包

【GDOI2007】JZOJ2020年8月10日提高組T1 夏娜的菠蘿包

題目

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。

題解

題意

給出\(n\)種麵包,每種麵包都有一個初始美味和遞減值,每天美味值將減去遞減值
\(m\)種搭配,每種搭配的美味值定義為這種搭配內的每個麵包的美味值
能選擇第\(i\)種搭配當且僅當這種搭配內的所有面包未被選過且美味值大於等於0
問最大的美味值

分析

很顯然可以暴力
每天暴力選取某種搭配,記錄答案,更新標記,美味值
然後取個最大的答案

Code

#include<cstdio>
#include<cstring>
using namespace std;
int n,m,i,j,ans,a[20],d[20],num[25],c[25],md[25][20];
bool b[20];
int read()
{
    int res;
    char ch;
    ch=getchar();
    res=0;
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9')
    {
        res=(res<<1)+(res<<3)+(ch-'0');
        ch=getchar();
    }
    return res;
}
bool judge(int x)
{
    int i;
    for (i=1;i<=num[x];i++)
        if (b[md[x][i]]==true) return false;
    return true;
}
bool pd(int x)
{
    int i;
    for (i=1;i<=num[x];i++)
        if (a[md[x][i]]<0) return false;
    return true;
}
void ins(int x)
{
    int i;
    for (i=1;i<=num[x];i++)
        b[md[x][i]]=true;
}
void del(int x)
{
    int i;
    for (i=1;i<=num[x];i++)
        b[md[x][i]]=false;
}
void inc()
{
    int i;
    for (i=1;i<=n;i++)
        a[i]+=d[i];
}
void dec()
{
    int i;
    for (i=1;i<=n;i++)
        a[i]-=d[i];
}
int get(int x)
{
    int res,i;
    res=0;
    for (i=1;i<=num[x];i++)
        res+=a[md[x][i]];
    return res;
}
void dg(int s)
{
    if (s>ans) ans=s;
    int i;
    for (i=1;i<=m;i++)
    {
        if (judge(i)==true&&pd(i)==true)
        {
            ins(i);
            s=s+get(i)+c[i];
            dec();
            dg(s);
            inc();
            s=s-get(i)-c[i];
            del(i);
        }
    }
}
int main()
{
    n=read();
    while (n)
    {
        memset(b,false,sizeof(b));
        for (i=1;i<=n;i++)
            a[i]=read(),d[i]=read();
        m=read();
        for (i=1;i<=m;i++)
        {
            num[i]=read();c[i]=read();
            for (j=1;j<=num[i];j++)
                md[i][j]=read();
        }
        ans=0;
        dg(0);
        printf("%d\n",ans);
        n=read();
    }
    return 0;
}