[USACO16OPEN]248 G 题解

题目


这是一个简化版的2048, 因为它只是线性结构,而不是二维结构.另外,只有相邻且相等的两个才能合并,且合并后得到的数字并非翻倍而是+1,如9与9合并为10.看到这道题首先想到了区间dp,但经过我的一通瞎搞仔细分析,发现没学过dp的人也能做出来--模拟大法.这题模拟的算法不会超时且它的时间复杂度(n * n)甚至比dp(n * n * n)还快.(其实是看到大佬们用的都是dp,本蒟蒻的dp过于...)

基本思路就是从数字小的开始合并. 首先我们知道最后它不一定会合并成一个数字, 但最多只会合并 n-1 次. 所以我们要先在外面套一层 1~n-1 的大循环. 接着可以分析出当合并到第i次的时候, 又 n-i+1 个数字, 所以最外面的一层循环可以从 n~2 , 方便.

	for(int i=n;i>1;--i){
		
	}

接着在每次循环都找到相连在一起的相同的且和最小的两个数, 将前一个记为 id (后一个记为 id+1).

	int minn=1e9;
	int id;
	for(int j=1; j<=i; ++j) {
		if(a[j]==a[j+1]&&a[j]<=minn) {
			minn=a[j];
			id=j;
		}
	}

然后我们就可以把两个数字合并后的值(存在了 minn 里面)存入 a[id] 里面, 并把它后面的全部向前位移一位.

	a[id]=minn+1;
	for(int j=id+1; j<=i; ++j) {
		a[j]=a[j+1];
		a[j+1]=0;
	}

这里有个要点, 如果寻找一遍后没有找到相连且相等的数对, 则要终止循环. 所以可以先将 id 赋值为 0, 循环一遍后若 id 仍为 0, 就终止循环.

最后我们只要再来一遍循环找到最大的那个就好了.

	int ans=0;
	for(int i=1; i<=n; ++i) {
		if(a[i]>ans) ans=a[i];
	}
	printf("%d",ans);
posted @ 2022-02-10 16:31  TuSalcc  阅读(123)  评论(0)    收藏  举报