【问题描述】
你是否听说过这个游戏?游戏者在一张特殊的表格中按照规则跳动,使得跳到的数字经过加号和减号的连接,
尽可能的逼近零。表格通常是如图a所示的形状,大小由中间一行的方格数N决定(图a就是一个N=4的例子)。游戏
者通常是从最下面的方格出发,按照如图b所示的规则在表格中跳动,当游戏者跳到最顶端的方格时,游戏结束。
在游戏未结束前,游戏者不允许跳到表格外。
将游戏者跳到的2N-1个数字依次写下来,在每两个相邻的数字中间加上加号或减号,使得计算结果最接近零。
例如对于图1所示的表格,最好的跳动及计算方案是:7+8+(-5)+(-2)-5-1-2=0
或7+10+(-7)-6+(-3)-3+2=0
或7+10+(-5)-10-5+1+2=0
或7+10+(-5)+(-2)-5-3-2=0。
【输入格式】
输入文件的第一行是N,接下来2N-1行给出了表格中每行的每个方格中的数字,第i+1行的第j个数字对应于表
格中第i行的第j个数字。文件中第二行的数字表示的是表格顶端的方格中的数字。文件中所有的数字都是整数,
同一行相邻的两个数字间用空格符隔开。
【输出格式】
输出文件只有一行,是你所求出的最接近零的计算结果的绝对值。
【输入样例1】
4
2
3 1
-3 5 7
6 10 -2 20
-7 -5 -8
10 8
7
【输出样例1】
0
【时空限制】
1S
512MB
【数据规模】
1≤n≤30
表格中的所有数字大于等于-50,小于等于50。
解:这里我们用f[i][j][k]来表示当我们跳到【i,j】这个位置的时候,在这之前是否能达到k的值。若可以则就加上自己的值往上一行能跳到的地方改为true。
(这个我解释不大清楚,所以还是写在程序注释里吧)
#include<iostream>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
int a[100][100],f[60][40][6001],n,tot;
bool check(int x)
{
if ((x>=0)&&(x<=2*tot))return true;
else return false;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int maxx=0;
for (int j=1;j<=i;j++)
{
scanf("%d",&a[i][j]);
a[i][j]=abs(a[i][j]);
maxx=max(maxx,a[i][j]);//分两部分输入
}
tot+=maxx;
}
for (int i=1;i<=n-1;i++)
{
int maxx=0;
for (int j=i;j<=n-1;j++)
{
scanf("%d",&a[i+n][j-i+1]);
a[i+n][j-i+1]=abs(a[i+n][j-i+1]);
maxx=max(maxx,a[i+n][j-i+1]);//奇怪的输入
}
tot+=maxx;
}
f[2*n-1][1][tot]=true;
//在跳到[2*n-1,1]之前我们的值可以达到0,所以赋值为true,
又因为c++不允许开负值的数组,所以我们把所有可能达到的值都加上一个tot,tot表示我们跳完后所能达到的最值。
int now=0;
for (int i1=n-1;i1>=1;i1--)
for (int j1=n-1;j1>=i1;j1--)
for (int k=2*tot;k>=0;k--)
{
int i=i1+n,j=j1-i1+1;
if (f[i][j][k])
{
now=k+a[i][j];
if (check(now))f[i-1][j][now]=f[i-1][j+1][now]=true;
//如果在这行之前已经达到k这个值了,且这个值没有出边界,那么跳到上一行之前就可以达到now这个值
now=k-a[i][j];
if (check(now))f[i-1][j][now]=f[i-1][j+1][now]=true;
}
}
//下面也是一样就是换一部分做做
for (int i=n;i>=1;i--)
for (int j=i;j>=1;j--)
for (int k=2*tot;k>=0;k--)
if (f[i][j][k])
{
now=k+a[i][j];
if (check(now))f[i-1][j][now]=f[i-1][j-1][now]=true;
now=k-a[i][j];
if (check(now))f[i-1][j][now]=f[i-1][j-1][now]=true;
}
int ans=2100000000;
for (int k=2*tot;k>=0;k--)
{
if (f[0][0][k]) ans=min(ans,abs(k-tot));
if (f[0][1][k]) ans=min(ans,abs(k-tot));
//看看最后最优解
}
cout<<ans<<endl;
return 0;
}