Codeforces Round #538 (Div. 2) D. Flood Fill(dp)

Description:

给出一个数列,先定义 component:就是数列中某一相连的数字相同的部分。

现在是一个游戏,初始时可以选择其中的一个数作为“中心”,然后每次操作可以改变包含该"中心"的一个component改变大小,问最少要操作多少次才能把所有的数都变成一样大小。

Input:

n

a[i] for(1<=i<=n)

Output:

answer

Analysis:

要用动态规划还是比较明显的:

这里一个重要的observation是,不论怎么搞,最终整个数列一定要么都和初始时左端的数相同,要么都和初始时右端的数相同。

设dp[L][R][dir] 为已经使得L到R内数字相同且 当dir=0时,数字都是初始时最左边的数,dir=1时,都是初始时最右边的数,

然后就好写了。

学习到的:这种中间到两边dp的递推顺序, 看别人用c++17写的代码有

int n=input<int>(); //这就直接输入了n

vector<int> a(n);

input_seq(a.begin(),a.end()) //这就直接输入了整个数列orz

#define _CRT_SECURE_NO_WARNINGS  
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<unordered_set>
#include<ctime>
#include<cstring>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 1 << 30;
const int maxn = 5005;
const int MOD = 1e9+7;
const double eps = 1e-6;

int n;
int a[maxn],dp[maxn][maxn][2];

int main()
{
	//freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
	while (scanf("%d", &n) == 1) {
		_rep(i, 1, n) scanf("%d", &a[i]);
		_rep(i,1,n)
			_rep(j, 1, n) {
			dp[i][j][0] = dp[i][j][1] = (i == j ? 0 : 0x3f3f3f3f);
		}

		for(int j=1;j<=n;++j)
			for (int i = j; i >= 1; --i) 
				for(int k=0;k<=1;++k){
					int c = (k == 0 ? a[i] : a[j]);
					if (i-1>=1) dp[i - 1][j][0] = min(dp[i - 1][j][0], dp[i][j][k]+(c!=a[i-1]));
					if (j + 1 <= n) dp[i][j + 1][1] = min(dp[i][j + 1][1], dp[i][j][k] + (c != a[j + 1]));
			}
		cout << min(dp[1][n][0], dp[1][n][1]) << endl;
	}


	return 0;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/87009102