NOIP模拟赛-密室(Room)

题目在这里

是道状压dp,我不会。。。。

那就搜索吧!骗暴力分,然后A了,0ms

爆搜过程

我们将每一个门的{内容物}压到结构体里,然后算一下  sub=(redkey+greenkey+whitekey-redlock-greenlock)(sub也加入结构体),如果是负数的话,那我们不需要考虑这扇门,因为我们不可能做一个决策使自己的物品变少,我们计算完后,按sub从大到小排序,因为sub大的最优的可能性最大

我们定义dfs(r,g,w)表示我们还有r个redkey,g个greenkey,w个whitekey,然后在进入下一个搜索循环前加一个剪枝,若剩下的所有Σ(sub>0)+r+g+w<=ans,也就是说假如剩下的门全部能打开,我们只考虑sub>0也就是key只增加的情况,都不会比之前的ans大的话,那么就不用继续向下搜索了

然后我们考虑搜索过程,找到一扇没有打开过的门,判断两种颜色的锁是否能开 if (w+r>=now.redlock) 这句话的意思是判断当前剩余的红钥匙和白钥匙之和是不是比门上的红锁多,多的话说明能开,那么让剩余的红钥匙减去开门需要的钥匙,若当前剩余红钥匙小于0,那么说明需要白钥匙,用剩余的白钥匙加上红钥匙小于0的值,然后将红钥匙置成0,然后继续判断greenlock,判断条件同上,修改条件同上,我们现在两种锁都开了,那么就可以获得门内的钥匙,所以每种颜色的钥匙加上门内的数量,然后进入下一层搜索

代码

//By AcerMo
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=50;
int vis[M];
int n,ans;
int re,gr,whi;
struct emm
{
    int sub;
    int rl,gl;
    int rk,gk,wk;
}qlm[M];
inline bool cmp(emm a,emm b){return a.sub>b.sub;}
inline int read()
{
    int x=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
    return x;
}
inline void dfs(int r,int g,int w)
{
    ans=max(ans,g+r+w);
    int sum=0;
    for (int i=1;i<=n;i++)
        if (!vis[i]) if (qlm[i].sub>0) sum+=qlm[i].sub;//剪枝
    if (g+r+w+sum<=ans) return ;
    for (int i=1;i<=n;i++)
    {
        if (vis[i]) continue;
        int nr=r,ng=g,nw=w;
        if (qlm[i].rl<=nr+nw)//判断红钥匙
        {
            nr-=qlm[i].rl;
            if (nr<0) nw+=nr,nr=0;//修改
            if (ng+nw>=qlm[i].gl)//绿钥匙
            {
                ng-=qlm[i].gl;
                if (ng<0) nw+=ng,ng=0;//修改
                nr+=qlm[i].rk;
                ng+=qlm[i].gk;
                nw+=qlm[i].wk;//加上门内钥匙
                vis[i]=1;
                dfs(nr,ng,nw);//dfs
                vis[i]=0;
            }
        }
    }
    return ;
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++) qlm[i].rl=read();
    for (int i=1;i<=n;i++) qlm[i].gl=read();
    for (int i=1;i<=n;i++) qlm[i].rk=read();
    for (int i=1;i<=n;i++) qlm[i].gk=read();
    for (int i=1;i<=n;i++) qlm[i].wk=read();
    for (int i=1;i<=n;i++)
    qlm[i].sub=(qlm[i].gk+qlm[i].rk+qlm[i].wk-qlm[i].rl-qlm[i].gl);//计算sub值
    re=read();gr=read();whi=read();
    sort(qlm+1,qlm+n+1,cmp);//按sub从小到大排序
    dfs(re,gr,whi);
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/80929333