Gym - 101196F Removal Game 区间dp

题目链接:点击查看

题意:

健健开发了一个游戏叫做<<者护守形隐>>,里面有一个情节是这样的,女主子纯藤武被坏人关在了密室里,作为男主的肖健当然要英雄救美。但是要打开密室的门,必须解开一道谜题。
门上有几个数字围成的一个圈,每次消除一个数字的代价是这个数字旁边的两个数字的gcd,当最后消的只剩两个数时,消除这两个数的代价就是这两个数字的gcd,密室的密码就是消除所有数字的最小代价。
请你帮助肖健解决这个问题
例如数字2,3,4,5,他可以以2的代价(gcd(2,4)==2)消除3,或者以1的代价(gcd(3,5)==1)消除4,或者以1的代价(gcd(3,5)==1)消除2

题解:因为他是一个圈,所以在1-n后面再加一个1-n,进行区间dp即可,dp[i][j]表示区间[i,j]还剩下i,j的情况下的最小花费,还有一个要注意的地方就是最后求值的时候。

给下我错的例子,for(int i = 1; i <= n; i++) ans = min(ans, dp[i][i + n - 1] + d[a[i]][a[i + n - 1]]);这是不对的,因为他是一个圈,最后也不知道会剩下哪两个,所以我们要枚举任意两个

for(int i = 1; i <= n; i++)
            for(int j = i + 1; j < i + n; j++)
                ans = min(ans, dp[i][j] + dp[j][i + n ] + d[a[i]][a[j]]);

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int n;
int a[210], dp[210][210], d[1100][1100];
int main()
{
	for(int i = 1; i <= 1000; i++)
		for(int j = 1; j <= 1000; j++)
			d[i][j] = __gcd(i ,j);
	while(~scanf("%d",&n) && n) {
		for(int i = 1; i <= n; i++) scanf("%d", &a[i]), a[i + n] = a[i];
		for(int i = 1;i <= n * 2; i++) {
			dp[i][i + 1] = 0;
			for(int j = i + 2; j <= n * 2; j++)
				dp[i][j] = INF;
		}
		for(int len = 3; len <= n; len++) {
			for(int i = 1; i <= n * 2; i++) {
				int j = i + len - 1;
				if(j > n * 2) break;
				for(int k = i + 1; k < j; k++)
					dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + d[a[i]][a[j]]);
			}
		}
		int ans = INF;
		for(int i = 1; i <= n; i++)
			for(int j = i + 1; j < i + n; j++)
				ans = min(ans, dp[i][j] + dp[j][i + n ] + d[a[i]][a[j]]);
		printf("%d\n", ans);
	}	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/89004073