题目链接:点击查看
题意:
健健开发了一个游戏叫做<<者护守形隐>>,里面有一个情节是这样的,女主子纯藤武被坏人关在了密室里,作为男主的肖健当然要英雄救美。但是要打开密室的门,必须解开一道谜题。
门上有几个数字围成的一个圈,每次消除一个数字的代价是这个数字旁边的两个数字的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;
}