【问题描述】

    你是否听说过这个游戏?游戏者在一张特殊的表格中按照规则跳动,使得跳到的数字经过加号和减号的连接,
尽可能的逼近零。表格通常是如图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。

c32df70f0a6082b8.jpg

【输入格式】

输入文件的第一行是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; }

 

posted on 2017-03-03 09:23  nhc2014  阅读(281)  评论(0编辑  收藏  举报