POJ 3628 Bookshelf 2 and POJ 1948 Triangular Pastures (01背包+枚举+思维)

POJ 3628 Bookshelf 2
题意 把奶牛堆到不低于书架的高度,并且尽量让奶牛堆到的高度和书架高度的差最小;(尽量让高度小)

01背包处理0-sum(所有奶牛高度之和),使当前高度被尽量填满,然后从书架高度向上枚举,找到第一个大于书架高度的值,作差即为答案。

AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int M=2e7+5;;
const int N=25;
int dp[M],w[N],v[N],sum[N];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&w[i] );
    for(int i=n;i>=1;i--)    ///后缀和
        sum[i]=sum[i+1]+w[i];
    for(int i=1;i<=n;i++)
    {
        int l=max(m-sum[i+1],w[i]);  ///01背包常数优化
        for(int j=sum[1];j>=l;j--)
            dp[j]=max(dp[j],dp[j-w[i] ]+w[i] );
    }
    int ans=0;
    for(int i=m;i<=sum[1];i++) ///因为dp[i]表示尽量填满高度 i 的最大值,所以以m(书架高度)为下界向上枚举
        if(dp[i]>=m)
        {
            ans=dp[i]-m;
            break;
        }
    printf("%d\n",ans);

    return 0;
}

POJ 1948 Triangular Pastures
一开始是打算开三维数组,分别代表三条边,dp[i][j][k]值为1 则表示能用这些线段组成 i,j,k大小的三条边,01背包处理,最后枚举i,j,k 并且判断能否组成三角形和这种组成方式是否存在。最后空间开不了这么大。
第二个想法是尽量让三条边相等这让能得到最大面积,便以sum/3为容量做两次背包,但是这种做法会出现很多answer=-1的情况 ,交上去WA。后来搜了一下题,看到二维两个字,便想到既然要求每一条线段都要使用,那么如果i,j能被线段组成,k就是sum-i-j的固定值了,所以完全可以降维。最后枚举所有组成,利用海伦公式得到最优答案。

AC代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int M=40*40+5;
const int N=40+5;
int dp[M][M],w[N];
int main()
{
    int n,sum=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
         scanf("%d",w+i);
         sum+=w[i];
    }
    int ans=-1;
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=sum/2;j>=0;j--)
        {
            for(int k=sum/2;k>=0;k--)
            {
                if(j>=w[i])				///状态转移方程
                    dp[j][k]=(dp[j-w[i] ][k]||dp[j][k]);
                if(k>=w[i])
                    dp[j][k]=(dp[j][k]||dp[j][k-w[i] ]);
            }
        }
    }
    double p=1.0*sum/2;
    for(int i=1;i<=sum/2;i++)
    {
        for(int j=1;j<=sum/2;j++)
        {
            int k=sum-i-j;
            if(!dp[i][j] ) continue;
            //printf("%d %d %d\n",i,j,k);
            if(i+j<k||i+k<j||j+k<i) continue;
            ans=max(ans,(int)(100.0*sqrt(p*(p-i)*(p-j)*(p-k) ) ) );
        }
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-12-11 21:15  DeepJay  阅读(81)  评论(0编辑  收藏  举报