游戏王的题解

目录

原题:

时间:1s   空间:256M

题目描述

输入格式

输出格式

样例输入

样例输出

题目大意:

主要思路:

dp转移:

dp初始化:

代码:


原题:

时间:1s   空间:256M
题目描述

大哈是个游戏王,尽管他的水平一言难尽,但他却总是这样自我称呼。小羽说如果你能把这个游戏通关了,你才算是个真的游戏王。这个游戏一开始你有n个连在一起的颜色块,第i个颜色块的颜色为a_i。如果从i到j的颜色都一样,就说明i到j属于同一个连通块。比如[5,5,5]属于同一个连通块,[4,3,9,9]有3个连通块。游戏开始前大哈可以选择任意一个位置作为起始点,然后开始游戏。游戏的每一轮大哈可以将包含起始点的连通块的颜色变成任意一种其他的颜色。问大哈能将整个数组变成从1到n的连通块所需要的最少回合数。

大哈是个游戏王,尽管他的水平一言难尽,但他却总是这样自我称呼。小羽说如果你能把这个游戏通关了,你才算是个真的游戏王。这个游戏一开始你有n个连在一起的颜色块,第i个颜色块的颜色为a_i。如果从i到j的颜色都一样,就说明i到j属于同一个连通块。比如[5,5,5]属于同一个连通块,[4,3,9,9]有3个连通块。游戏开始前大哈可以选择任意一个位置作为起始点,然后开始游戏。游戏的每一轮大哈可以将包含起始点的连通块的颜色变成任意一种其他的颜色。问大哈能将整个数组变成从1到n的连通块所需要的最少回合数。

输入格式

第一行一个整数n(1 \le n \le 5000

第二行n个整数a_i1\le a_i \le 5000

输出格式

一个整数代表最少回合数

样例输入

4

5 2 2 1

样例输出

2

题目大意:

给你n个数,要你求把所有数变成相同一个数所需的最小操作数(每次操作可以将包含起点的连通块变为同一个数)

主要思路:

这题很难想到区间dp,我们用dp[l][r] 表示把l~r里的数变为同一个数的最小操作数,首先把每个连通块去重(就像把【2,2,3,3,2,2,4,4,4,4】变成【2,3,2,4】。

dp转移:

  1. v[l] == v[r] 那么就要dp[l][r] = dp[l+1][r-1]+1;注意:a[l+1]!=a[l],a[r-1]!=a[r]图:(画的有点草,谢谢谅解) 游戏王的题解_第1张图片 转移一图例
  2. 否则dp[l][r] = min(dp[l+1][r],dp[l][r-1])+1;图:(画的有点草,谢谢谅解) 游戏王的题解_第2张图片 转移2图例

剩下就没有什么好说的了

dp初始化:

dp[i][i] = 0把自己变成同一个数需要0步(i<=n)

代码:

#include
using namespace std;
vector v; 
int dp[5010][5010];
int main()
{
	int n;
	cin>>n;
	v.push_back(0);
	int num=-1;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		if(i == 1)
		{
			num=x;
		}
		else
		{
			if(x == num)
			{
				
			}
			else
			{
				v.push_back(x);
				num = x;
			}
		}
	}
	memset(dp,0x3f,sizeof(dp));
	for(int i=1;i<=v.size();i++)
	{
		dp[i][i] = 0;
	}
	for(int len=2;len<=v.size();len++)
	{
		for(int l=1;l+len-1<=v.size();l++)
		{
			int r=l+len-1;
			if(v[l] == v[r]&&dp[l-1][r-1]!=v[l]&&dp[l-1][r-1]!=v[r])
			{
				dp[l][r] = dp[l+1][r-1]+1;
			}
			else
			{
				dp[l][r] = min(dp[l+1][r],dp[l][r-1])+1;
			}
		}
	}
	cout<

你可能感兴趣的:(算法,c++,动态规划,题解)