spoj14846 Bribe the Prisoners

看来我还是太菜了,这么一道破题做了那么长时间......

传送门

分析

我首先想到的是用状压dp来转移每一个人是否放走的状态,但是发现复杂度远远不够。于是我们考虑区间dp,dpij表示i到j区间的所有罪犯全部放走的最小花费,于是我们可以将一个区间(i,j)分为(i,k-1),(k+1,j)和k这个点,表示先取走点k的人,这样这个区间就被分成了两个,于是我们便可以转移的。详见代码。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int pl[1100],dp[1100][1100];
inline void init(){
      memset(dp,0x7f,sizeof(dp));
}
int main(){
      int n,m,i,j,k,t; 
      scanf("%d",&t);
      for(int _=1;_<=t;_++){
          init();
          scanf("%d%d",&m,&n);
          for(i=1;i<=n;i++)
            scanf("%d",&pl[i]);
          pl[n+1]=m+1;
          for(i=1;i<=n;i++)
            dp[i][i]=pl[i+1]-pl[i-1]-2;
          for(i=2;i<=n;i++)
            for(j=1;j+i-1<=n;j++){
                dp[j][j+i-1]=min(dp[j+1][j+i-1],dp[j][j+i-2]);
              for(k=j+1;k<j+i-1;k++)
                dp[j][j+i-1]=min(dp[j][j+i-1],dp[j][k-1]+dp[k+1][j+i-1]);
              dp[j][j+i-1]+=pl[j+i]-pl[j-1]-2;
            }
          printf("Case #%d: ",_);
          printf("%d
",dp[1][n]);
      }
      return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9462279.html