【例9.6】挖地雷
时间限制: 1000 ms 内存限制: 65536 KB
【题目描述】在一个地图上有n个地窖(n≤200),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径,并规定路径都是单向的,且保证都是小序号地窖指向大序号地窖,也不存在可以从一个地窖出发经过若干地窖后又回到原来地窖的路径。某人可以从任意一处开始挖地雷,然后沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使他能挖到最多的地雷。
【输入】第一行:地窖的个数;第二行:为依次每个地窖地雷的个数;下面若干行:xiyi //表示从xi可到yi,xi<yi。最后一行为"0 0"表示结束。
【输出】k1−k2−…−kv //挖地雷的顺序挖到最多的雷。
【输入样例】
`6`
`5 10 20 5 4 5`
`1 2`
`1 4`
`2 4`
`3 4`
`4 5`
`4 6`
`5 6`
`0 0`
【输出样例】
`3-4-5-6`
`34`
【类型】
DP(动态规划),邻接矩阵(存有向图)
【思路】
设dp[i]表示i点可以挖到的地雷的最大值。
因为dp[j](0<j<i)中已经存了j点可以挖到的地雷的最大值,所以可以让j遍历1~i-1,若j可以到i(a\[j][i]==1)并且从j点获得的最大值大于原有最大值(dp[j]+b[i]>dp[i]),则更新dp\[i](dp[i]=dp[j]+b[i])。
总结一下,主代码为:
```c++
for (int i = 1; i <= n; i++)
dp[i] = b[i];
for (int i = 2; i <= n; i++)
for (int j = 1; j < i; j++)
if (a[j][i] && dp[j] + b[i] > dp[i])
dp[i] = dp[j] + b[i];
```
因为题目要求输出顺序,所以定义一个前缀数组p[i],存放i的前缀。用p找到答案所在位置的祖宗,顺便记录其长辈,最后倒着输出记录下的内容即可。
【代码】
```c++
#include <bits/stdc++.h>
using namespace std;
long long n, b[202], dp[202], p[202], d[202], x, y, ans, t, c;
bool a[202][202];
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> b[i];
while (1)
{
cin >> x >> y;
if (x == 0 && y == 0)
break;
a[x][y] = 1;
}
for (int i = 1; i <= n; i++)
dp[i] = b[i];
for (int i = 2; i <= n; i++)
for (int j = 1; j < i; j++)
if (a[j][i] && dp[j] + b[i] > dp[i])
{
p[i] = j;
dp[i] = dp[j] + b[i];
}
for (int i = 1; i <= n; i++)
if (dp[i] > ans)
{
ans = dp[i];
t = i;
}
while (1)
{
if (t == 0)
break;
d[++c] = t;
t = p[t];
}
for (int i = c; i > 1; i--)
cout << d[i] << "-";
cout << d[1] << endl;
cout << ans;
return 0;
}
```