zoukankan      html  css  js  c++  java
  • 转化为分组背包 zoj 3769

    题目链接:https://vjudge.net/problem/ZOJ-3769

    题意:现在你要去打怪,你有13种装备,每件装备会有伤害和防御两种属性,一般来说,每种装备只可以装备一件,但是特别的,戒指(Finger)你可以同时装备两个,左右手各一个,然后对于“Two-Handed”类的装备,如果你装备这种装备,那么你就不可以装备"Shield", "Weapon"这两种,反之,如果你装备了"Shield", "Weapon"中的任意一种,那么你就不可以装备“Two-Handed”类的装备,现在需要我们求出在达到m点以上防御值的情况下可以达到的最大攻击值。如果无法达到m点防御值,则输出-1。

    思路:这题可以转化为分组背包,但是又两个问题要解决,一个是Finger类装备,我们可以把Finger类的装备两两组合,加入Finger类里面,这样就把两个Finger类的装备转化为了一个,然后对于"Shield", "Weapon"这两类,我们也是可以两两组合加入“Two-Handed”类里面去的,当然,为了避免其中一种装备的数量为0,所以可以先将"Shield", "Weapon"这两类分别加入“Two-Handed”,然后在加入两两组合的。我一开始是用结构体数组储存的,一直超时,看了大佬博客,说要先处理数量多的那一类,这样可以节省时间,觉得有道理,但是用结构体数组改了还是一直超时(果然,大佬的代码和我的就是不一样),最后重写代码,改成和他们一样用vector储存就过了,不知道为啥。如果有谁知道的,可以提醒一下我,感谢感谢。

    这里开二维数组,其中把防御看做背包容量,但是我们不知道背包容量的上限,题目只说了要大于等于m点防御值,所以我们把m以上的都看成m(为啥别人脑洞就这么大),由于在第k组拿装备的时候需要知道第k-1组的值,所以状态转移方程就是dp[k][i+w[j]]=max(dp[k][i+w[j]],dp[k-1][i]+v[j])。

    代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<set>
    #include<cstdio>
    #include<string>
    #include<deque> 
    using namespace std;
    typedef long long LL;
    #define eps 1e-8
    #define INF 0x3f3f3f3f
    #define maxn 50005
    /*struct point{
        int u,w;
    };
    bool operator <(const point &s1,const point &s2)
    {
        if(s1.v!=s2.v)
        return s1.v>s2.v;
        else
        return s1.u>s2.u;
    }*/
    struct node{
        int v,w;
    };
    int n,m,k,t;
    map<string,int>mp;
    vector<node>ve[20];
    string ss[20]={" ","Two-Handed","Finger", "Head", "Shoulder", "Neck", "Torso", 
    "Hand", "Wrist", "Waist", "Legs","Feet", "Shield", "Weapon"};
    int dp[15][maxn];
    void init()
    {
        for(int i=1;i<=13;i++){//给装备编号 
            mp[ss[i]]=i;
        }
    }
    int main()
    {
        init();
        cin>>t;
        while(t--)
        {
            cin>>n>>m;
            for(int i=0;i<=15;i++){
                ve[i].clear();
            }
            string s;
            int w,v;
            for(int i=1;i<=n;i++){
                cin>>s>>v>>w;
                int id=mp[s];
                ve[id].push_back((node){v,w});
            }
            memset(dp,-1,sizeof(dp));//初始化所有状态都不可达 
            dp[0][0]=0;//初始化 
            
            for(int i=0;i<ve[12].size();i++){//"Shield", "Weapon"合并到“Two-Handed” 
                ve[1].push_back(ve[12][i]);
            }
            int num1=ve[12].size();
            int num2=ve[13].size();
            for(int i=0;i<num2;i++){
                ve[1].push_back(ve[13][i]);
                for(int j=0;j<num1;j++){
                    ve[1].push_back((node){ve[13][i].v+ve[12][j].v,ve[13][i].w+ve[12][j].w});
                }
            }
            
            num1=ve[2].size();
            for(int i=0;i<num1;i++){//"Finger"合并 
                for(int j=i+1;j<num1;j++){
                    ve[2].push_back((node){ve[2][i].v+ve[2][j].v,ve[2][i].w+ve[2][j].w});
                }
            } 
            
            
            for(int k=1;k<=11;k++){//枚举组 
                for(int i=0;i<=m;i++){//枚举防御值 
                    dp[k][i]=max(dp[k][i],dp[k-1][i]);//现在状态的初值从前一状态来 
                    if(dp[k-1][i]==-1)//如果前一状态不可达 
                    continue;
                    for(int j=0;j<ve[k].size();j++){//如果前一状态可以到达,那么可以在前一状态的基础上在当前组
                    //拿一件装备 
                        int min1=min(m,i+ve[k][j].w);
                        dp[k][min1]=max(dp[k][min1],dp[k-1][i]+ve[k][j].v);
                    }
                }
            }
            cout<<dp[11][m]<<endl;
        }
        return 0;
    }

    结构体数组一直超时的代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<set>
    #include<cstdio>
    #include<string>
    #include<deque> 
    using namespace std;
    typedef long long LL;
    #define eps 1e-8
    #define INF 0x3f3f3f3f
    #define maxn 50005
    /*struct point{
        int u,w;
    };
    bool operator <(const point &s1,const point &s2)
    {
        if(s1.w!=s2.w)
        return s1.w>s2.w;
        else
        return s1.u>s2.u;
    }*/
    map<string,int>mp;
    int dp[15][maxn];
    int n,m,k,t;
    struct node{
        int num;
        int w[3005];
        int v[3005];
    }zu[20];
    string s[18]={" ", "Two-Handed"," ","Head", "Shoulder", "Neck", "Torso", "Hand", "Wrist", "Waist", 
    "Legs", "Feet", "Finger", "Shield", "Weapon"};
    void init()
    {
        for(int i=1;i<=14;i++)
        {
            mp[s[i]]=i;
        }
    }
    void combine_finger()
    {
        int c=zu[12].num;
        if(c==0)
        return;
        if(c==1)
        {
            zu[2].num++;
            zu[2].w[1]=zu[12].w[1];
            zu[2].v[1]=zu[12].v[1];
            return;
        }
        for(int i=1;i<c;i++){
            for(int j=i+1;j<=c;j++){
                zu[2].num++;
                int k=zu[2].num;
                zu[2].w[k]=zu[12].w[i]+zu[12].w[j];
                zu[2].v[k]=zu[12].v[i]+zu[12].v[j];
            }
        }
        return;
    }
    void combine_two()
    {
        int a=zu[13].num;
        int b=zu[14].num;
        for(int i=min(a,1);i<=a;i++){
            for(int j=min(b,1);j<=b;j++){
                zu[1].num++;
                int c=zu[1].num;
                zu[1].w[c]=zu[13].w[i]+zu[14].w[j];
                zu[1].v[c]=zu[13].v[i]+zu[14].v[j];
            }
        }
        return;
    }
    int main()
    {
        init();
        scanf("%d",&t);
        while(t--)
        {
            memset(dp,0,sizeof(dp));
            scanf("%d%d",&n,&m);
            string ss,w,v; 
            int a,b;
            for(int i=1;i<=n;i++){
                cin>>ss>>a>>b;
                int id=mp[ss];
                zu[id].num++;
                int c=zu[id].num;
                zu[id].v[c]=a;
                zu[id].w[c]=b;
            }
            combine_finger();
            combine_two();
            memset(dp,-1,sizeof(dp));
            dp[0][0]=0;
            for(int k=1;k<=11;k++){
                for(int i=0;i<=m;i++){
                    dp[k][i]=max(dp[k][i],dp[k-1][i]);
                    if(dp[k-1][i]==-1)
                    continue;
                    for(int j=1;j<=zu[k].num;j++){
                        int min1=min(m,i+zu[k].w[j]);
                        dp[k][min1]=max(dp[k][min1],dp[k-1][i]+zu[k].v[j]);
                    }
                }
            }
            cout<<dp[11][m]<<endl;
        }
        return 0;
    }
  • 相关阅读:
    发送trim值
    关一些时钟
    不同频率下的pwm配置
    c#鼠标在控件上面,然后显示文字
    C#通过文件路径截取对应的文件夹路径
    C#随机生成连续多少个十六进制数字
    C#检测串口被拔掉等一些触发事件合集
    c#按键Up和Down对Textbox的内容加1减1
    软件架构师工作历程
    软件架构阅读6
  • 原文地址:https://www.cnblogs.com/6262369sss/p/9923630.html
Copyright © 2011-2022 走看看