HDU 4283 You Are the One(区间DP)

题目链接

这个我是用记忆化搜索写的。比赛的时候卡死在这里,以为是个简单的二维DP,思维被局限了,以前也没怎么做过区间DP,没做出,不过还是觉得理解了状态状态转移,代码什么的都是很短。dp[x][y][z]的意义是在x-y这一段上,前面已经有z-1个人唱歌了,所取得的最小值,这个DFS的写的有点感觉像是树形DP,递推能力太搓了。

 1 #include <iostream>

 2 #include <cstdio>

 3 #include <cstring>

 4 #include <cstdlib>

 5 #include <cmath>

 6 #include <map>

 7 #include <queue>

 8 #include <set>

 9 #include <vector>

10 #define INF 1

11 #define LL __int64

12 using namespace std;

13 int dp[101][101][101];

14 int p[101];

15 int dfs(int x,int y,int z)

16 {

17     int i,ans;

18     if(x > y)//注意这种情况

19     return 0;

20     if(x == y)

21     {

22         dp[x][y][z] = p[x]*z;

23         return dp[x][y][z];

24     }

25     if(dp[x][y][z] != INF)

26     return dp[x][y][z];

27     ans = z*p[x] + dfs(x+1,y,z+1);//初始假设第x个人在第z位置唱歌

28     for(i = x+1;i <= y;i ++)

29     {

30         ans = min(ans,dfs(x+1,i,z)+dfs(i+1,y,z+i-x+1)+p[x]*(z+i-x));//枚举第x个人在z+i-x位置唱歌,则区间被分成了两块。

31     }

32     dp[x][y][z] = ans;

33     return ans;

34 }

35 int main()

36 {

37     int t,i,j,k,n,num = 0;

38     scanf("%d",&t);

39     while(t--)

40     {

41         scanf("%d",&n);

42         for(i = 1;i <= n;i ++)

43         scanf("%d",&p[i]);

44         for(i = 0;i <= n;i ++)//求最小,初始化为很大的数

45         {

46             for(j = 0;j <= n;j ++)

47             {

48                 for(k = 0;k <= n;k ++)

49                 dp[i][j][k] = INF;

50             }

51         }

52         printf("Case #%d: ",++num);

53         printf("%d\n",dfs(1,n,0));

54     }

55     return 0;

56 }

 

你可能感兴趣的:(HDU)