区间DP。dp[i][j]表示第i到第j个全部释放最小费用。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int INF=0x7FFFFFFF; const int maxn=100+10; int T,P,Q; int a[maxn]; int dp[maxn][maxn]; void read() { scanf("%d%d",&P,&Q); for(int i=1;i<=Q;i++) scanf("%d",&a[i]); sort(a+1,a+1+Q); a[0]=0; a[Q+1]=P+1; } void init() { memset(dp,0,sizeof dp); for(int i=1;i<=Q;i++) for(int j=i;j<=Q;j++) dp[i][j]=INF; } void work() { for(int i=1;i<=Q;i++) { for(int j=1;j<=Q;j++) { int st=j,en=st+i-1; if(en>Q) continue; if(i==1) { dp[st][en]=a[st]-a[st-1]-1+a[st+1]-a[st]-1; continue; } for(int k=st;k<=en;k++) { dp[st][en]=min( dp[st][en], dp[st][k-1]+dp[k+1][en]+(a[en+1]-1-a[st-1])-1 ); } } } printf("%d\n",dp[1][Q]); } int main() { // freopen("D:\\test.in","r",stdin); // freopen("D:\\test.out","w",stdout); scanf("%d",&T); for(int Case=1;Case<=T;Case++) { read(); init(); printf("Case #%d: ",Case); work(); } return 0; }