题目链接:http://codeforces.com/gym/101196
题目大意:有n个数字成环,删掉一个数字的代价是周围俩数的gcd,只剩俩数字的时候用这俩数字的gcd作为代价,问删掉所有数字的最小代价
题目思路:考虑区间dp,dp[i][j]表示i,j区间内,删的只剩下i和j的最小代价,当长度为1和2时,dp值为0,其他时候枚举中间的点作为最后一个被删除的点,那么dp[i][j]就是dp[i][k]+dp[k][j]+gcd(a[i],a[j]),最后枚举最后被删除的两个点即可
以下是代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define inf 0x3f3f3f3f
const int MAXN = 1005;
int n,a[MAXN],dp[MAXN][MAXN];
int main()
{
while(~scanf("%d",&n)&&n){
rep(i,1,n)scanf("%d",&a[i]),a[i+n]=a[i];
memset(dp,0x3f,sizeof(dp));
rep(i,1,n){
rep(j,1,2*n){
int x=j,y=j+i-1;
if(y>2*n)break;
if(x==y||x+1==y)dp[x][y]=0;
else{
rep(k,x+1,y-1)dp[x][y]=min(dp[x][y],dp[x][k]+dp[k][y]+__gcd(a[x],a[y]));
}
}
}
int ans=inf;
rep(i,1,n){
rep(j,i+1,i+n-1){
ans=min(ans,dp[i][j]+dp[j][i+n]+__gcd(a[i],a[j]));
}
}
printf("%d\n",ans);
}
return 0;
}