Posts Tagged ‘背包’

POJ 1837 Balance解题报告(动态规划)

见原文
NENU Goodness
题目来源:POJ 1837 Balance
http://acm.pku.edu.cn/JudgeOnline/problem?id=1837

解法类型:动态规划

题目大意:
输入一个天平若干(<=20)挂钩的位置,将若干(<=20)砝码挂到天平上,问有多少种使天平挂平衡的方法。

解题思路:
用一个二维数组t[x][y+4000]记录挂x个砝码时到y这个值的方法数,将砝码一一挂上,最后记录所有砝码都挂上时的t[x][4000]的值,详见代码。

提交情况:
Wrong Answer若干:开始的时候没想到用二维数组,试图通过两个一维数组不断互相更新,由于操作繁琐,过需花费时间,导致不能遍历每个位置,为了省时,又引 入 记录 值不为0 的t数组相应位置 的数组。导致操作更加繁琐,代码过长,思路虽没什么问题,但零星的错误实在难以找到,最终只好更换思路。

注意:
动态规划类题目状态标记方法 以及标记数组各元素之间的关系 比较多样灵活, 难以想到,这是重点也是难点。

代码:

源程序:
#include <iostream>

using namespace std;

int w[21],h[21],t[21][8000];

/*w数组用来记录砝码的重量,
h数组用来记录天平挂钩的位置,
t的第一位维用来记录已挂上的挂钩的数目
第二维用来记录通过挂砝码
可以到达相应值的方法数*/

int main()
{
int c,g,i,j,k;
while(cin>>c>>g)
{
for(i=1;i<=c;i++) cin>>h[i];        //输入挂钩位置和砝码的重量
for(i=1;i<=g;i++) cin>>w[i];
memset(t,0,sizeof(t));                        //初始化可达数数组
for(i=1;i<=c;i++) t[1][w[1]*h[i]+4000]++;

/*挂第一个砝码时对可达数 数组
进行相应的修改 其中+4000
(可知若想使得天平平衡一面最多挂到的值为4000)
是为了将所有值都转到正数组中 方便处理
开始的时候没想到 用了两个数组
这也给编码和调试带来了极大的不便*/

for(i=2;i<=g;i++)                //将剩余的砝码一一挂上
for(j=1;j<=c;j++)        //循环所有挂钩的位置
for(k=1;k<=8000;k++)
if(t[i-1][k]) t[i][k+w[i]*h[j]]+=t[i-1][k];

/*循环所有值  找到 挂  上一个  砝码后可以达到的值,
然后挂当前砝码,得到 挂当前砝码后
计算得到的对应值 的可达数*/

cout<<t[g][4000]<<endl;

//输出所有砝码都挂上 平衡位置所对应的可达数即为 平衡的方法数
}
return 0;
}

另可见,我(Charlie)在上边有些论述:

http://www.5ushare.com/bbs/viewthread.php?tid=56&extra=page%3D1

http://www.5ushare.com/bbs/viewthread.php?tid=29&extra=page%3D1

Incoming search terms for the article:

POJ1836【动态规划】

原文见
原题描述:
Alignment
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 1188 Accepted: 239
Description
In the army, a platoon is composed by n soldiers. During the morning inspection, the soldiers are aligned in a straight line in front of the captain. The captain is not satisfied with the way his soldiers are aligned; it is true that the soldiers are aligned in order by their code number: 1 , 2 , 3 , . . . , n , but they are not aligned by their height. The captain asks some soldiers to get out of the line, as the soldiers that remain in the line, without changing their places, but getting closer, to form a new line, where each soldier can see by looking lengthwise the line at least one of the line’s extremity (left or right). A soldier see an extremity if there isn’t any soldiers with a higher or equal height than his height between him and that extremity.

Write a program that, knowing the height of each soldier, determines the minimum number of soldiers which have to get out of line.
Input
On the first line of the input is written the number of the soldiers n. On the second line is written a series of n floating numbers with at most 5 digits precision and separated by a space character. The k-th number from this line represents the height of the soldier who has the code k (1 <= k <= n).

There are some restrictions:
• 2 <= n <= 1000
• the height are floating numbers from the interval [0.5, 2.5]
Output
The only line of output will contain the number of the soldiers who have to get out of the line.
Sample Input
8
1.86 1.86 1.30621 2 1.4 1 1.97 2.2
Sample Output
4

题目大意:
给出系列数字,要求求出一个最长串,使得任意一个数字都不在两个大于等于它的数字中间
题意理解
这题主要是要求一个不降序列和一个不升序列的序列,由此,可以看到跟2533(最长不降序列)很相像。实际上,也只要考虑几个小问题就行了。
解题思路:
在2533(最长不降序列)中,我们只要用一个1000的数组就行了。其状态转移方程为
F(K) = MAX(F(A1),F(A2)..F(Ai)) + 1,其中0=<A1=<A2..<Ai=<N,Seq[k] >= F(Ai)。即第K个数字及其之前数字的最长不降序列为其之前的某个小于它的数字的最长不降序列加一。
对于这题,则可用一个二维数组。其第一维与2533相同,储存其最长不降序列;第二维则储存最长不升序列。具体为:
F(K,0)=MAX(F(A1,0)…F(Ai,0)) + 1; F(K,1) = MAX(F(B1,0)..F(Bi,0),F(A1,1)..F(Bi,1)) + 1.
另外,还有一点需要注意,就是 5 5 5中间的5 的处理。。。
具体代码如下:
AC代码:

复制内容到剪贴板

代码:

#include <iostream>
using namespace std;

int main(){
int n;
double Num[1000];
while(cin >> n){
for(int i = 0; i < n; ++i){
cin >> Num[i];
}
int Res[2001][3];
for(int i = 0; i < n; ++i){
Res[i][0] = 1;
Res[i][1] = 1;
Res[i][2] = 0;
}
for(int i = 0; i < n; ++i){
for(int k = 0; k < i; ++k){
if((Num[i] < Num[k]) || (!Res[k][2] && Num[i] == Num[k])){
if(Res[i][1] < Res[k][0] + 1){
Res[i][1] = Res[k][0] + 1;
Res[i][2] = 1;
}
if(Res[i][1] < Res[k][1] + 1){
Res[i][1] = Res[k][1] + 1;
Res[i][2] = 1;
}
}else if(Num[i] > Num[k]){
if(Res[i][0] < Res[k][0] + 1){
Res[i][0] = Res[k][0] + 1;
}
}
}
}
int max = 0;
for(int i = 0; i < n; ++i){
if(Res[i][0] > max){
max = Res[i][0];
}
if(Res[i][1] > max){
max = Res[i][1];
}
}
cout << n – max << endl;
}
}

Incoming search terms for the article: