HDU 5074 Hatsune Miku(DP)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5074

题目大意:给定一个长度为n的序列c[i],该序列为一个乐谱。我们的任务是要给这个序列补上音符。c[i]的数值有两种情况:-1、不是-1。不是-1的这个位置的音符已经确定,不能再更改。是-1的这个位置音符可以任意选择。可以选择的音符有m种,编号为1-m。

             当乐谱序列完成后,会有一个得分产生(即这乐谱的优美程度)。得分为score(c[1],c[2])+score(c[2],c[3])+...+score(c[n-1],c[n])。其中score[i][j]在题中已经给出。我们的任务是要把这个得分总和最大化。

思路:显然是DP。由于我之前回顾了区间DP,因而……先想到了区间DP。但是这样显然不行。从DP的无后效性考虑,我大概想到了方法。。

        设f[i][j]为序列c[1]到c[i],并且c[i]=j时可以得到的最大得分。则可分4种情况讨论:

        1、c[i - 1] !=-1, c[i] != -1.这是最简单的情况,定死的。直接算即可。

    2、c[i - 1] == -1, c[i] != -1.此时只要对f[i - 1][j]进行枚举更新即可。

        3、c[i - 1] != -1,c[i] == -1.这种情况对f[i][j]进行枚举,从f[i - 1][c[i - 1]]更新即可。

        4、c[i - 1] == -1,c[i] != -1.该情况的状态转移方程为f[i][j] = max(f[i - 1][k] + score[k][j]).

   时间复杂度为O(NM^2)

   代码送上(代码中的a[i][j]即为这里的score[i][j])

 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <functional>
 6 
 7 using namespace std;
 8 
 9 #define REP(i,n)        for(int i(0); i <  (n); ++i)
10 #define rep(i,a,b)        for(int i(a); i <= (b); ++i)
11 #define INF    1 << 30
12 
13 
14 const int Q    =    1000        +    10;
15 int f[Q][Q], a[Q][Q];
16 int c[Q];
17 int n, m;
18 int T;
19 
20 int main(){
21 
22     scanf("%d", &T);
23     REP(Case, T){
24         memset(f, 0, sizeof f); memset(a, 0, sizeof a); memset(c, 0, sizeof c);
25         scanf("%d%d", &n, &m);
26         rep(i, 1, m) rep(j, 1, m) scanf("%d", &a[i][j]);
27         rep(i, 1, n) scanf("%d", c + i);
28         rep(i, 1, n) f[1][i] = 0;
29         rep(i, 2, n){
30             if (c[i] != -1 && c[i - 1] != -1) f[i][c[i]] = f[i - 1][c[i - 1]] + a[c[i - 1]][c[i]];
31             if (c[i] != -1 && c[i - 1] == -1) rep(j, 1, m) f[i][c[i]] = max(f[i][c[i]], f[i - 1][j] + a[j][c[i]]);
32             if (c[i] == -1 && c[i - 1] != -1) rep(j, 1, m) f[i][j] = f[i - 1][c[i - 1]] + a[c[i - 1]][j];
33             if (c[i] == -1 && c[i - 1] == -1) rep(j, 1, m) rep(k, 1, m) f[i][j] = max(f[i][j], f[i - 1][k] + a[k][j]);
34         }
35         int ans = 0;
36         if (c[n] == -1) rep(i, 1, m) ans = max(ans, f[n][i]); else ans = f[n][c[n]];
37         printf("%d\n", ans);
38     }
39     
40     
41     return 0;
42     
43 }

 

posted @ 2016-09-28 20:10  cxhscst2  阅读(273)  评论(0编辑  收藏  举报