杭电4341-Gold miner(分组背包)

本文介绍了一种特殊的01背包问题——分组背包,并详细解释了其状态转移方程及解决思路。通过实例代码展示了如何将斜率相同的元素归类并进行求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


这是一道分组背包的题,这题开始乍一看以为是01背包,但是看了数据才明白是一道分组背包。

分组背包其实是一种变相的01背包。

只不过01背包是每件物品只有一件,可以选择取或不取。

分组背包则是有若干类物品,,每类物品中有若干个各不相同的物品,但是每类物品里只能选一样.................



他的状态转移方程是这样的:

f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}


所以这题有两个难点,一个是把斜率相同的金块归类到一个类里面,

而后就是实现这个状态方程:


一言不合直接上代码;

(有点遗憾的就是太耗时了,想不到优化的方法)

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
#define N 220
struct Node 
{
    int x,y;
    int v,t;
}node[N];
bool cmp(Node p1,Node p2)
{
    int x1=p1.x;
    int y1=p1.y;
    int x2=p2.x;
    int y2=p2.y;
    if(y1*x2==y2*x1)    //把斜率相同的金块排序,紧挨在一起
        return y1<y2;   //注意理解一下,下面归类有用
    return y1*x2<y2*x1; //这里依据什么排序其实无所谓,因为主要是实现让斜率相同的金块紧挨排序 
}
int group[N][N];
int cnt;
int dp[50000];
int solve(int T)
{
    int t,i,j,k;
    memset(dp,0,sizeof(dp));
    for(i=0;i<=cnt;i++)
    {
        for(t=T;t>=0;t--)
        {
            for(j=1;j<=group[i][0];j++)//group[i][0]代表的是第i类的有几个物品
            {
                k=group[i][j];
                if(t-node[k].t>=0)
                {
                    dp[t]=max(dp[t],dp[t-node[k].t]+node[k].v);//状态转移方程
                }
            }
        }
    }
    return dp[T];
}
int main()
{ 
     int n,T,i;
     int c=0;
     while(~scanf("%d %d",&n,&T))
     {
        for(i=0;i<n;i++)
            scanf("%d %d %d %d",&node[i].x,&node[i].y,&node[i].t,&node[i].v);
        sort(node,node+n,cmp);
        cnt=-1;
        for(i=0;i<n;i++)
        {
            cnt++;
            group[cnt][0]=0;
            group[cnt][++group[cnt][0]]=i;//每类物品至少有一个以上的物品,标记第一个物品是第几个物品
            int x1=node[i].x;
            int y1=node[i].y;
            int a=node[i].t;
            int b=node[i].v;

            for(i+=1;i<n;i++)//因为上面排序使斜率相同的金块紧挨,所以只要在当前金块往下找找到斜率
            {
                int x2=node[i].x;
                int y2=node[i].y;
                a+=node[i].t;
                b+=node[i].v;
                if(y1*x2==y2*x1)
                {
                    group[cnt][++group[cnt][0]]=i;////斜率相同,为同一类的金块,把第几块位置标记入类
                    node[i].t=a;
                    node[i].v=b;
                }
                else//找到斜率不一样的就说明下面没有斜率相同的金块了,跳出
                {
                    i--;
                    break;
                }
            }
        }
        printf("Case %d: ",++c);
        printf("%d\n",solve(T));
     }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值