CH Round #53—密室
题目
有N个密室,3种钥匙(红色,绿色,白色)和2种锁(红色,绿色),红色钥匙只能开红色的锁,绿色钥匙只能开绿色的锁,白色钥匙可以开红色的锁和绿 色的锁,一把钥匙使用一次之后会被扔掉。每个密室由一扇门锁着,上面锁着一些红色和绿色的锁,房间里面放着一些红色、绿色和白色的钥匙,打开密室你将拿走 这些钥匙。你可以以任意顺序打开密室,但是同一个密室只能打开一次。初始你已经有了一些钥匙了,现在你要进行决策,使得最终剩下的钥匙尽量的多,注意,你 不一定要打开所有的房间,你可以在任意时刻结束。输出你最多能有几把钥匙。
输入格式
第一行一个整数N,表示有N个密室。
第二行N个整数,第i个数表示第i扇门上有ai把红色的锁。
第三行N个整数,第i个数表示第i扇门上有bi把绿色的锁。
第四行N个整数,第i个数表示第i个密室有ci把红色的钥匙。
第五行N个整数,第i个数表示第i个密室有di把绿色的钥匙。
第六行N个整数,第i个数表示第i个密室有ei把白色的钥匙。
第七行三个整数k0,k1,k2,依次表示初始你拥有的红色、绿色、白色钥匙的数量。
输出格式
输出一个整数,表示你最多能有几把钥匙。
样例输入
3
1 2 3
0 4 9
0 0 10
0 8 9
1 0 8
3 1 2
样例输出
8
题解
状压dp
f[i][j]表示经过门的集合为i,红钥匙数为 j 时白钥匙最多有多少
因为我们要尽量多用红绿钥匙,可以打开更多的门,有更多的选择
代码
#include<cstring>
#include<cstdio>
#include<iostream>
#define fo(i,n) for(int i=0;i<n;i++)
using namespace std;
const int N=15;
int dR[N],dG[N],rR[N],rG[N],rW[N],ky[N],n,f[20000][200],z;
int main()
{
scanf("%d",&n);
fo(i,n) cin>>dR[i];
fo(i,n) cin>>dG[i];
fo(i,n) cin>>rR[i];
fo(i,n) cin>>rG[i];
fo(i,n) cin>>rW[i];
cin>>ky[0]>>ky[1]>>ky[2];
int sum=ky[0]+ky[1]+ky[2];
memset(f,-1,sizeof f);
f[0][ky[0]]=ky[2];
fo(i,1<<n){
int k0=ky[0],k1=ky[1],r=sum;
fo(j,n)
if(i>>j&1){
k0+=rR[j];
r+=rR[j]+rG[j]+rW[j]-dR[j]-dG[j];
}
for(int j=0;j<=k0;j++){
if(f[i][j]==-1) continue;
int fr=f[i][j];
int k=r-fr-j;
fo(l,n){
if(i>>l&1) continue;
int r=max(0,dR[l]-j),g=max(0,dG[l]-k);
int &q=f[i|(1<<l)][max(0,j-dR[l])+rR[l]];
if(fr>=r+g)
q=max(q,fr-r-g+rW[l]);
}
z=max(z,j+k+fr);
}
}
cout<<z<<endl;
}