【问题描述】 | ||
一个特殊的数字阵列,共有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 |
【输出样例】 | |||
0 |
【数据范围】 | |||
1<=N<=30 |
|
|
| |
|
【来源】 |
| |
|
|
题目类型:动态规划
这是一道难题!
根据题目描述,我们知道,每个数字在-50~50之间,一共最多有2*30-1=59行,所以走完全部取得的数字结果范围一定在-50*59~50*59之间,即在-2950~2950之间。我们发现,这个数字并不大,由此我们可以得到方程f(i,j,k)表示走到(i,j)时取得数经过运算能否得到k,若能,则值为1,否则为0;
所以状态转移方程为 f(i , j , k)={f(i+1 , j , k+a[i][j]) || f(i+1 , j , k-a[i][j]) || f(i+1 , j+1 , k+a[i][j]) || f(i+1 , j+1 , k-a[i][j])} (i<=N)
f(i , j , k)={f(i+1 , j , k+a[i][j]) || f(i+1 , j , k-a[i][j]) || f(i+1 , j-1 , k+a[i][j]) || f(i+1 , j-1 , k-a[i][j])} (N<i<=2*N-1) (这种情况要单独讨论j=1 和 j=2*N-1的情况)
程序从第2*N-2层开始往上搜。所以边界条件为 f(2*N-1 , 1 , a[2*N-1][1])=1
最后的答案就是从i=0开始第一个f(1 , 1 , i)=1 或者 f(1 , 1 , -i)=1的i值即是答案
关于负数下标应该用宏来处理更为简单!
程序:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define f(i,j,k) d[(i)][(j)][(k)+2000] //定义宏
using namespace std;
int N;
int a[70][50];
int d[70][50][5500];
int tot=0;
void Ready()
{
scanf("%d",&N);
for(int i=1;i<=N;i++)
for(int j=1;j<=i;j++)
{
scanf("%d",&a[i][j]);
tot+=abs(a[i][j]);
}
for(int i=1;i<N;i++)
for(int j=1;j<=N-i;j++)
{
scanf("%d",&a[i+N][j]);
tot+=abs(a[i+N][j]);
}
memset(d,0,sizeof(d));
}
void Working()
{
f(2*N-1,1,a[2*N-1][1])=1;
for(int i=2*N-2;i>=N;i--)
for(int j=1;j<=2*N-i;j++)
for(int k=-tot;k<=tot;k++)
{
if(j>1 && j<2*N-i)
{
if(f(i+1,j-1,k-a[i][j]) || f(i+1,j-1,k+a[i][j]) || f(i+1,j,k-a[i][j]) || f(i+1,j,k+a[i][j]))f(i,j,k)=1;
}
if(j==1)
{
if(f(i+1,j,k-a[i][j]) || f(i+1,j,k+a[i][j]))f(i,j,k)=1;
}
if(j==2*N-1)
{
if(f(i+1,j-1,k-a[i][j]) || f(i+1,j-1,k+a[i][j]))f(i,j,k)=1;
}
}
for(int i=N-1;i>=1;i--)
for(int j=1;j<=i;j++)
for(int k=-tot;k<=tot;k++)
{
if(f(i+1,j+1,k-a[i][j]) || f(i+1,j+1,k+a[i][j]) || f(i+1,j,k-a[i][j]) || f(i+1,j,k+a[i][j]))f(i,j,k)=1;
}
int ans;
for(int i=0;i<=tot;i++)
{
if(f(1,1,i) || f(1,1,-i))
{
ans=i;
break;
}
}
printf("%d",ans);
}
int main()
{
Ready();
Working();
return 0;
}
by:重庆一中吴松隐