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
",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
",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
",ans);
return 0;
}