您的位置:首页 > 其它

重庆一中Vijos 【训练题】步步为零 P1428 题解

2014-10-19 12:10 134 查看

题解:

此题是一道比较简单的一道动态规划题目

设状态转移方程时容易想到的是 d[i,j] = 从最下面一格走到(i,j)的最佳值,但这样定义显然行不通,因为“最佳值”定义得太抽象,没办法描述。

所以应该定义为:d[i,j,k] = 从最下面一格走到(i,j)经过一系列加减拿到k可不可行。

但是此题的方程比较繁琐,要分两种情况,这里不细说了,大家可以在代码的第70-90行去看。

在做这道题的时候我遇到了一个问题,就是ready(0函数计算所有和的值的时候,在第40行。

一开始j没有初始化我就在使用,其实是一个笔误,我本来准备写1的。在本机上完全可以测试通过,但交上题库总是内存越界,最上面的check我就是写来检查越界的。遗憾的是check没有检查到任何错误,

因为在我的编译器上j被初始化了…………最后我把程序一小段一小段的交到题库上才发现是这里错了,调了接近一个小时…………orz

代码:

#define MAXN 35
#define MAXL 6010
#define ADD 3005

#define dp(i,j,k) d[(i)][(j)][(k)+ADD]
#define check if(i>=MAXN+MAXN || i<0 || j<0 || j>=MAXN || k+ADD<0 || k+ADD>=MAXL)throw "add error"

#include
#include
#include

using namespace std;

int d[MAXN+MAXN][MAXN][MAXL];
int a[MAXN+MAXN][MAXN];
int N;
int tot;

void input()
{
int i,j;
scanf("%d",&N);
for(i=1;i<=N;i++)
for(j=1;j<=i;j++)
scanf("%d",&a[i][j]);
for(i=N-1;i>0;i--)
for(j=1;j<=i;j++)
scanf("%d",&a[N+N-i][j]);
}

void ready()
{
int i,j,max,k=0;
memset(d,0,sizeof(d));
dp(N+N-1,1,a[N+N-1][1]) = 1;

tot = 0;
for(i=1;i<=N;i++)
{
max = a[i][1]; //开始写的max = a[i][j]; 教训啊教训
for(j=1;j<=i;j++)
{
check;
if(a[i][j]>max)max = a[i][j];
}
tot += max;
}
for(i=N-1;i>0;i--)
{
max = a[N+N-i][1];
for(j=1;j<=i;j++)
{
check;
if(a[N+N-i][j]>max)max = a[N+N-i][j];
}
tot += max;
}
}

void work()
{
int i,j,k;
for(i=N+N-2;i>=N;i--)
{
for(j=1;j<=N+N-i;j++)
{
for(k=-tot;k<=tot;k++)
{
check;
dp(i,j,k) = dp(i+1,j, k-a[i][j]) ||
dp(i+1,j, k+a[i][j]) ||
dp(i+1,j-1,k-a[i][j]) ||
dp(i+1,j-1,k+a[i][j]);
}
}
}
for(;i>=1;i--)
{
for(j=1;j<=i;j++)
{
for(k=-tot;k<=tot;k++)
{
check;
dp(i,j,k) = dp(i+1,j, k-a[i][j]) ||
dp(i+1,j, k+a[i][j]) ||
dp(i+1,j+1,k-a[i][j]) ||
dp(i+1,j+1,k+a[i][j]);
}
}
}
}

void output()
{
int i,j=0,k=0;
for(i=0;;i++)
{
if(dp(1,1,i) || dp(1,1,-i))break;
check;
}
printf("%d\n",i);
}

int main()
{
freopen("in.txt","r",stdin);

input();
ready();
work();
output();
return 0;
}


题目描述:

题目网站

【训练题】步步为零 
 
 时间限制:2秒  内存限制:128M
 
   
  
 【问题描述】 
   一个特殊的数字阵列,共有2*N-1行,每个方格中有一个数码Ai(-50<=Ai<=50),例如N=4的情况。

                    


  HB从最下面方格出发,每次可以跳到上一行与自己所在格子相邻的其中一个方格内(例如在最下面的7中,可以跳到上一行的10和8中),他每到达一个方格,就将该方格的数记录下来。当他到达最顶格子的时候,拿出记录数字,可以在任意两个数字间添加“+”或“-”号,使得计算的结果m最接近0。现在请你帮助他。
   
 【输入格式】 
   第一行是N,接下来2N-1行由上到下给出了表格中每行的每个方格中的数字,第i+1行的第j个数字对应于表格中第i行的第j个数字。     
   
 【输出格式】 
   输出只有一行,是你所求出的最接近零的计算结果的绝对值  
   
 【输入样例】 
 4

2

3 1

-3 5 7

6 10 -2 20

-7 -5 -8

10 8

7
<
4000
td width="712" height="20" align="left" class="style2" valign="top" colspan="2">
 
  
 【输出样例】 
 0
   
 【数据范围】 
   1<=N<=30
   
 【来源】 
   最优解7+8+(-5)+(-2)-5-1-2=0  

  或7+10+(-7)-6+(-3)-3+2=0

  或7+10+(-5)-10-5+1+2=0

  或+10+(-5)+(-2)-5-3-2=0

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: