UVA - 12589 Learning Vector (01背包)

问题

n个向量,选择k个,连成一条折线,使得折线和x轴之间的面积最大

分析

开始想的是状压dp,发现n太大了,换种思路
这道题是01背包的变形,只不过多了一个高度,新增加的一个向量带来的权重和尾部高度H,向量所在矩形大小W有关,所以需要多记录一个维度,记录上个状态的尾部高度
(得到最优解要排序,按照向量的斜率从大到小排序,按照顺序选择,计算才是最优解,因为两个向量,先后不同,结果也不同,例如A:(3,4)和B:(4,3),顺序是A,B,结果是56,顺序是B,A,结果是42 ,所以,综上,要先确定选择的顺序,转化为01背包,依次进行选择)

#include<iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=52,INF=0x3f3f3f3f;

struct Vector{
    int x,y,s;
    Vector(int x=0,int y=0,int s=0):x(x),y(y),s(s){}
    bool operator < (const Vector &rhs) const {
        return rhs.x*y>rhs.y*x;   //比较斜率,斜率大的在前面
    }
}v[maxn];
//dp[i][j]代表选择了i个向量,最终高度j,得到的对应面积,i就相当于01背包中的容量,j是用来辅助计算的
//滚动数组
int kase=1,T,n,k,dp[maxn][maxn*maxn];

int main(void){
    scanf("%d",&T);
    while(kase<=T){
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;++i){
            scanf("%d%d",&v[i].x,&v[i].y);
            v[i].s=v[i].x*v[i].y;
        }
        sort(v,v+n);  //按照斜率进行排序,斜率大的在斜率小的前面,才是最优解
        memset(dp,-1,sizeof(dp));
        dp[0][0]=0;
        int p=0,ans=-1;
        for(int h=0;h<n;++h){ //遍历所有的向量,可选择,也可不选
            Vector &temp=v[h];
            for(int i=k-1;i>=0;--i){  //已经选择了i个向量,逆序更新,绝对不能递增
                for(int j=2500;j>=0;--j){   //这个地方无所谓,可以递增
                    if(dp[i][j]>=0)
                        dp[i+1][j+v[h].y]=max(dp[i+1][j+v[h].y],dp[i][j]+2*j*v[h].x+v[h].s);
                }
            }
        }
        for(int j=2500;j>=0;--j){
            ans=max(ans,dp[k][j]);
        }
        printf("Case %d: %d\n",kase++,ans);
    }
}
发布了50 篇原创文章 · 获赞 0 · 访问量 700

猜你喜欢

转载自blog.csdn.net/zpf1998/article/details/104125777