• 滚动数组(细节)(坑点)


    滚动数组中本次0/1用完后,对后面结果无贡献了,一定要记得清零,否则会不断累积(一共就两个数0/1,循环多了肯定都快填满了)
    那道题是这样的:(步步为零)

    步步为零(dp ⋆⋆)

    你是否听说过这个游戏?游戏者在一张特殊的表格中按照规则跳动,使得跳到的数字经过加号和减号的连接,尽可能的逼近零。表格通常是如图 1.1所示的形状,大小由中间一行的方格数 N 决定(图 1.1 就是一个 N=4的例子)。
    游戏者通常是从最下面的方格出发,按照如图 1.2所示的规则在表格中跳动,当游戏者跳到最顶端的方格时,游戏结束。在游戏未结束前,游戏者不允许跳到表格外。将游戏者跳到的 2∗N−1个数字依次写下来,在每两个相邻的数字中间加上加号或减号,使得计算结果最接近零。例如对于图 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。)

    Input

    输入文件的第一行是 (N(N<=50)),接下来 (2∗N−1) 行给出了表格中每行的每个方格中的数字,第 (i+1) 行的第 (j) 个数字对应于表格中第 (i) 行的第 (j) 个数字。文件中第二行的数字表示的是表格顶端的方格中的数字。文件中所有的数字都是整数,同一行相邻的两个数字间用空格符隔开。

    Output

    输出文件只有一行,是你所求出的最接近零的计算结果的绝对值。

    Sample Input

    4
    2
    3 1
    -3 5 7
    6 10 -2 20
    -7 -5 -8
    10 8
    7

    Sample Output

    0

    Hint

    表格中的所有数字大于等于−50,小于等于50。
    (本博客主要强调细节,好吧写完博客之后我觉得上句话并不恰当)
    (f[i][j][k]= 0 或 1),(f[i][j][k]= = 0)表示最后一个数一直加到(a[i][j])(还没加(a[i][j]))不能达到k,(f[i][j][k] = = 1)表示可以达到 (k)
    我们不处理负数,所以对于(k),我们算出一个最大区间([-mid,mid]),然后每次求出来的和都向上平移mid以保证正数。
    转移:(我们是从下向上转移/递推)

    • 对于下半部分 由 (f[i][j][k] = = 1) 可以得到
      (-> f[i-1][j][k+a[i][j]] = 1;)
      (-> f[i-1][j+1][k+a[i][j] = 1;)
      (-> f[i-1][j][k-a[i][j]] = 1;)
      (-> f[i-1][j+1][k-a[i][j] = 1;)
    • 对于上半部分,同理:由 (f[i][j][k] = = 1) 可以得到
      (-> f[i-1][j][k+a[i][j]] = 1;)
      (-> f[i-1][j-1][k+a[i][j] = 1;)
      (-> f[i-1][j][k-a[i][j]] = 1;)
      (-> f[i-1][j-1][k-a[i][j] = 1;)
      最后统计第0行的结果,不统计第一行是因为 (f[1][1][k]) 还没有算上 (a[1][1]) ,算上 (a[1][1]) 的结果转移到f[0][1][k]和 (f[0][0][k]) 中了。
      每阶段只与上一阶段相关,滚动数组压维,每次转移完后没用了注意清零

    Code

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int Max,mid,n,st,a[52][52],f[2][52][10000];
    int A(int x){
    	return x>=0?x:-x;
    }
    int main(){
    //	freopen("1.in","r",stdin);
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i){
    		Max=0;
    		for(int j=1;j<=i;++j){
    			scanf("%d",&a[i][j]);
    			a[i][j]=A(a[i][j]);
    			Max=a[i][j]>Max?a[i][j]:Max;
    		}
    		mid+=Max;
    	}
    	for(int i=1;i<n;++i){
    		Max=0;
    		for(int j=1;j<=n-i;++j){
    			scanf("%d",&a[n+i][j]);
    			a[n+i][j]=A(a[n+i][j]);
    			Max=a[n+i][j]>Max?a[n+i][j]:Max;
    		}
    		mid+=Max;
    	}
    	int next;
    	f[st][1][mid]=1;
    	for(int i=n*2-1;i>=n;--i,st^=1){
    		for(int j=1;j<=(n<<1)-i;++j){
    			for(int k=0;k<=(mid<<1);++k){
    				if(f[st][j][k]){
    					next=k+a[i][j];
    					f[st^1][j][next]=f[st^1][j+1][next]=1;
    					next=k-a[i][j];
    					f[st^1][j][next]=f[st^1][j+1][next]=1;
    					f[st][j][k]=0;//记得清零aaaaa
    				}
    			}
    		}
    	}
    	for(int i=n-1;i>=1;--i,st^=1){
    		for(int j=1;j<=i;++j){
    			for(int k=0;k<=(mid<<1);++k){
    				if(f[st][j][k]){
    					next=k+a[i][j];
    					f[st^1][j][next]=f[st^1][j-1][next]=1;
    					next=k-a[i][j];
    					f[st^1][j][next]=f[st^1][j-1][next]=1;
    					f[st][j][k]=0;//记得清零aaaaa
    				}
    			}
    		}
    	}
    	int ans=0x3f3f3f3f;
    	for(int i=0;i<=(mid<<1);++i){
    		if(f[st][1][i])ans=ans<A(mid-i)?ans:A(mid-i);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Websocket --socket.io的用法
    Vuex中mapState的用法
    vue中关于computed的一点理解
    webuploader大文件分片,多线程总结
    pdf的使用遇到的问题
    单文件WebUploader做大文件的分块和断点续传
    webUploader大文件断点续传学习心得 多文件
    iframe子页面与父页面元素的访问以及js变量的访问
    pwa 集合
    mpvue 转小程序实践总结
  • 原文地址:https://www.cnblogs.com/Lour688/p/13256490.html
Copyright © 2020-2023  润新知