【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;
}