[NOI1995]石子合併(區間DP)
阿新 • • 發佈:2018-11-25
題目連結:
思路:
區間DP經典例題,可以把前n-1堆石子一個個移到第n個後面,那樣環就變成了線,即現在有2*n-1堆石子需要合併。
程式碼:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <set> #include <queue> #include <algorithm> using namespace std; typedef long long ll; const int MAX = 200 + 10; const int inf=1e9+7; int n; int a[MAX]; int dpmax[MAX][MAX]; int dpmin[MAX][MAX]; int main() { scanf("%d",&n); memset(dpmax,0,sizeof(dpmax)); memset(dpmin,0x3f,sizeof(dpmin)); for(int i=0;i<n;i++){ scanf("%d",&a[i]); dpmin[i][i]=0; } for(int i=n;i<2*n-1;i++){ a[i]=a[i-n]; dpmin[i][i]=0; } for(int i=1;i<2*n-1;i++) a[i]+=a[i-1]; for(int len=2;len<=n;len++){ for(int i=0;i<2*n-1;i++){ int j=i+len-1; if(j>=2*n-1) break; for(int k=i;k<j;k++){ dpmin[i][j]=min(dpmin[i][j],dpmin[i][k]+dpmin[k+1][j]+a[j]-a[i-1]); dpmax[i][j]=max(dpmax[i][j],dpmax[i][k]+dpmax[k+1][j]+a[j]-a[i-1]); } } } int ansmax=0,ansmin=0x3f3f3f3f; for(int i=0;i<n;i++){ ansmax=max(ansmax,dpmax[i][i+n-1]); ansmin=min(ansmin,dpmin[i][i+n-1]); } printf("%d\n",ansmin); printf("%d\n",ansmax); return 0; }