题目描述燕姿在桥的这一端,而xx在桥的另一端。这座桥非常特殊,桥面是由2N-1个方格组成的,每个方格里写有一个数码Ai(-50<=Ai<=50)。如下是N=4时的情况。可以认为燕姿从最下面出发。每一次,她可以向上跳到与自己所在方格相临的其中一个方格内(例如在最下面的7中,可以跳到上一行的10和8中)。当燕姿跳到最顶端的方格后,她就不能再移动了。(在未到顶端前,不允许跳到表格外。)每在一格内,都要把格内的数字写下来。 但是,仅仅到达顶端是不够的。桥会向对岸的xx询问一个数字k,燕姿到达顶端后,拿出写下来的数字,可以在任意两个数字间添加“+”或“-”号,使得计算的结果m最接近k。经过桥的判断,如果对于桥上的方格m是最接近k的数字,那么燕姿就可以通过桥和xx相遇,否则……… (为了让燕姿能更容易地通过,xx给出的数字总是0)你的任务,就是帮助燕姿找出这个最接近k的m.
输入
输入的第一行是N(1<=N<=30),接下来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
提示:
最优解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
题解:设num为桥上某一行某一列的数字dp[i][j][k]:第i行第j列所有数字是否可行dp[i][j][k]=f[i-1][j-1][ k-num ] || f[i-1][j-1][ k+num ] || f[i-1][j][ k-num ] || dp[i-1][j][ k+num ]
但是f数组过于巨大肯定是开不下,
递推的一维最多用到i和i-1,
于是可以使用滚动数组节约空间
dp[i&1][j][k]=f[!(i&1)][j-1][ k-num ] || f[!(i&1)][j-1][ k+num ] || f[!(i&1)][j][ k-num ] || dp[!(i&1)][j][ k+num ]
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; const int N=50; const int M=3000; const int Mid=M>>1; int n, num, ans, u, d; bool dp[2][N][M]; int main() { scanf( "%d%d", &n, &num ); dp[1][1][ Mid-num ]=1; //数组的下标不能为负数, 就将1500作为0分界线, 1500以下为负数, dp[1][1][ Mid+num ]=1;//至于为什么用1500, 因为一层的最大和为30*50=1500 for( int i=2; i<=n; i++ ) { memset( dp[i&1], 0, sizeof dp[i&1] ); for( int j=1; j<=i; j++ ) { scanf( "%d", &num ); for( int k=N; k<=M-N; k++ )//num最大为50 if( dp[!(i&1)][j-1][k+num] || dp[!(i&1)][j-1][k-num] || dp[!(i&1)][j][k+num] || dp[!(i&1)][j][k-num] ) dp[i&1][j][k]=1; } } for( int i=n-1; i>=1; i-- ) { memset( dp[i&1], 0, sizeof dp[i&1] ); for( int j=1; j<=i; j++ ) { scanf( "%d", &num ); for( int k=0; k<N; k++ ) //num最大为50 if( dp[!(i&1)][j][k+num] || dp[!(i&1)][j+1][k+num] ) dp[i&1][j][k]=1; for( int k=N; k<=M; k++ ) if( dp[!(i&1)][j][k+num] || dp[!(i&1)][j][k-num] || dp[!(i&1)][j+1][k+num] || dp[!(i&1)][j+1][k-num] ) dp[i&1][j][k]=1; } } for( u=Mid; u<=M; u++ ) if( dp[1][1][u] ) break; for( d=Mid; d>=0; d-- ) if( dp[1][1][d] ) break; ans=min( u-Mid, Mid-d ); printf("%d\n",ans); return 0; }
f(i,j,k)=f(i−1,j−1,k−inp[i][j])||f(i−1,j−1,k+inp[i][j])||f(i−1,j,k−inp[i][j])||f(i−1,j,k+inp[i][j]的递但是f数
[BZOJ1510]遇见
最新推荐文章于 2021-05-31 12:08:17 发布