Greedy Tino动态规划问题-搬橘子
- 例7.6 Greedy Tino(九度教程第100题)
题目大意:给定n个橘子的重量,要求从这些橘子中选出若干个分成两堆,使得这两堆的重量相同,问这两堆橘子的总重量是多少?
解法:使用动态规划。dp[i][j]表示放入第i个橙子之后,第一堆比第二堆重j,两堆的总重量,dp[][]的每一个值代表一个状态,求出所有状态之后,dp[n][0]/2即为所得。
代码如下:
//动态规划问题
#include<bits/stdc++.h>
using namespace std;
#define INF 0x7fffffff
#define OFFSET 2000//因为两堆的重量差j可能是负数,所以选j+OFFSET作为数组下标
int ganju[101];//柑橘重量
int dp[101][4001];//状态转移数组,其中dp[i][j]表示放入第i个橙子之后,第一堆比第二堆重j,两堆的总重量
int main()
{
int T;
int cases=0;
cin>>T;
while(T--){
int n;//n个柑橘
cin>>n;
int cnt=0;//记录有多少个重量非0的柑橘
bool havezero=false;
for(int i=1;i<=n;i++)
{
cin>>ganju[++cnt];//输入橘子的重量
if(ganju[cnt]==0)
{
cnt--;
havezero=true;
}
}
n=cnt;
//初始化
for(int i=-2000;i<=2000;i++)
dp[0][i+OFFSET]=-INF;//状态不存在
dp[0][0+OFFSET]=0;//选0个橘子,两堆重量差是0时,重量和也是0
//算法
for(int i=1;i<=n;i++){//每一个橘子
for(int j=-2000;j<=2000;j++){//每种重量
int tmp1=-INF,tmp2=-INF;
if(j+ganju[i]<=2000 && dp[i-1][j+ganju[i]+OFFSET]!=-INF)
tmp1=dp[i-1][j+ganju[i]+OFFSET]+ganju[i];//有第一堆转化而来
if(j-ganju[i]>=-2000 && dp[i-1][j-ganju[i]+OFFSET]!=INF)
tmp2=dp[i-1][j-ganju[i]+OFFSET]+ganju[i];//由第二堆转化而来
if(tmp1<tmp2)
tmp1=tmp2;5
if(tmp1<dp[i-1][j+OFFSET])
tmp1=dp[i-1][j+OFFSET];//与柑橘不放入任何堆的原状态比较,取最大值
dp[i][j+OFFSET]=tmp1;//加入这个橘子后,当前状态值为三个状态转化而来的最大值
}
}
cases++;
cout<<"Case"<<cases<<":";
if(dp[n][0+OFFSET]==0)
puts(havezero==true?"0":"-1");//puts()自动换行
else
cout<<dp[n][0+OFFSET]/2<<endl;
}
return 0;
}
阿里云成长空间 738人发布