zoukankan      html  css  js  c++  java
  • 平常练习动归(2.步步为零)———bool型动归

    【问题描述】

        你是否听说过这个游戏?游戏者在一张特殊的表格中按照规则跳动,使得跳到的数字经过加号和减号的连接,
    尽可能的逼近零。表格通常是如图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; }
  • 相关阅读:
    vue --- 全局弹窗,只调用对应实例
    代理相关;win操作
    mongoBD + node + express
    菜鸟初学 node 推荐 亲测easy
    H5 ---- 点击遍历所有标签,复制对应的文本
    async与await初步应用
    C# Enum 添加自定义Attribute,然后通过泛型与反射的方式得到事先定义的标记
    VS2013 C# 调用 cognex 的QuickBuild做程序时发生一个错误
    C# 获取数组的内存地址
    利用反射插入数据库与更新数据库
  • 原文地址:https://www.cnblogs.com/2014nhc/p/6494399.html
Copyright © 2011-2022 走看看