AHU-727 美妙音乐 【DP】

Description
西瓜和Roll组团去冒险,他们打开了隐藏的密门,发现了矮人矿洞的秘密。那是多年前由矮人王亲自下令改建的密室,据说只有最美妙的音乐可以指引他们找到宝藏。
一首音乐是最美妙的,当且仅当每两个相邻音符的和谐度之和最大。西瓜发现了一张矮人公认的最美和谐度表harmony。西瓜发现,他可以使用m种音符构造音乐,最终构成的音乐共包含n个音符。西瓜兴致勃勃地谱出了最美妙的音乐,不幸的是,在矮人矿洞Roll发现矮人们的音乐有固定的模板,他们应当按照矮人们的模板再谱出一首曲子。由于西瓜的谱曲天赋有限,一天只能谱写一首曲子,他们想尽快进入那个矿洞,只有找你来帮助他们。
 
Input
输入数据第一行,包含一个整数T,为数据组数(1≤T≤10)。
对于每组数据,第一行包含两个整数n和m,(1≤n≤100,1≤m≤50)。
接下来m行,每行包括m个用空格隔开的整数,第i行第j列表示harmony(i,j)(0≤harmony(i,j) ≤100)。
接下来一行包含n个用空格隔开的整数ai(-1≤ai≤m且ai≠0),ai为-1时代表你可以随意指定音符,ai>0时你不能改变音符。

 

Output
对于每组数据,输出包括两个用空格隔开的整数x,y。x为在矮人模板下最大的和谐度,y为没有模板限制时最大的和谐度。

 

Sample Input
1
42 2
31 96
18 96
2 -1 -1 2 -1 -1 -1 -1 2 -1 -1 1 -1 1 -1 -1 -1 2 1 -1 -1 -1 -1 1 2 2 -1 -1 1 2 2 -1 1 2 -1 2 -1 2 1 2 -1 -1

 

Sample Output
3390 3936
 
  

思路:

比较容易想到是一道DP,用f(i,j)代表到第i个音符时选择音符j的最大和谐度,k代表第i-1个音符,则不按模板时,有转移方程:
        f(i,j) = max1<=k<=m(f(i,j), f(i-1,k)+h(k,j))
按照模板时,只要ai>0时将j!=ai时的f(i,j)全部赋值为-inf再按上式递推就行


Code:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define INF 0x3f3f3f3f
 4 int f[105][55], g[105][55], h[55][55], a[105];
 5 
 6 int main() {
 7     ios::sync_with_stdio(false);
 8     int T, n, m;
 9     cin >> T;
10     while (T--) {
11         memset(f, 0, sizeof(f));
12         memset(g, 0, sizeof(g));
13         cin >> n >> m;
14         for (int i = 1; i <= m; ++i)
15             for (int j = 1; j <= m; ++j)
16                 cin >> h[i][j];
17         for (int i = 1; i <= n; ++i) cin >> a[i];
18         int ans1 = 0, ans2 = 0;
19         for (int i = 2; i <= n; ++i) 
20             for (int j = 1; j <= m; ++j)
21                 for (int k = 1; k <= m; ++k) {
22                     f[i][j] = max(f[i][j], f[i-1][k] + h[k][j]);
23                     ans2 = max(ans2, f[i][j]);
24                 }
25         if (a[1] > 0)
26             for (int i = 1; i <= m; ++i)
27                 if (a[1] != i) g[1][i] = -INF;
28         for (int i = 2; i <= n; ++i) {
29             if (a[i] > 0) {
30                 for (int j = 1; j <= m; ++j)
31                     if (j != a[i]) g[i][j] = -INF;
32                     else for (int k = 1; k <= m; ++k)
33                         g[i][j] = max(g[i][j], g[i-1][k] + h[k][j]);
34             }
35             else {
36                 for (int j = 1; j <= m; ++j)
37                     for (int k = 1; k <= m; ++k)
38                         g[i][j] = max(g[i][j], g[i-1][k] + h[k][j]);
39             }
40         }
41         for (int i = 1; i <= m; ++i) ans1 = max(ans1, g[n][i]);
42         cout << ans1 << " " << ans2 << endl;
43     }
44 
45     return 0;
46 }

 

转载于:https://www.cnblogs.com/robin1998/p/6601567.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值