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 }