首先介绍动态规划的基本思路:
1.分析问题是否有最优子结构,然后刻画最优解的结构特征
2.递归地定义最优解的值
3.计算最优解的值,通常采用自下而上的方法
4.利用计算出来的值构造一个最优解
接下来分析本问题:地窖地雷问题
【题目描述】
在一个地图上有n个地窖(n<=200),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径,并规定路径都是单向的,且保证都是小序号地窖指向在序号地窖,也不存在可以从一个地窖出发经过若干地窖后又回到原来地窖的路径。某人可以从任一处开始挖地雷,然后沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使他能挖到最多的地雷。
【输入】
第一行:地窖的个数;
第二行为依次每个地窖地雷的个数;
下面若干行:
xi yi //表示从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
题解:f[i]表示第i个地窖作为起点最多可得挖多少, next[i]表示第i个地雷的下一点,map[x][y]表示x是否可以通向y
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int danger[205],f[205],map[205][205],next[205];
int main()
{
int n,sum=0,k=0;//k最后起到了标记最优起点的作用
cin>>n;
memset(f,0,sizeof(f));//初始化,使f数组置为0
for(int i=1;i<=n;i++){
cin>>danger[i];//输入每个地窖的地雷数
f[i]=danger[i];//未出发时,即f最多有其自身的地雷数
}
int x,y;
while(cin>>x>>y)//输入路径关系
{
if(!x&&!y)break;
map[x][y]=1;//第x个地窖可通向第y个地窖即使数组置1
}
next[n]=0;//最后一个地窖无下一点的地窖,故为0
for(int i=n-1;i>0;i--)
for(int j=i+1;j<=n;j++)//此for循环用于得出以第i个地窖为起点的最优下一点选择,由下往上不断寻找最优路径
if(map[i][j]&&f[j]+danger[i]>f[i])//表示以第j个地窖为起点的一条可通边的地雷总数是否大于前一个点为起点的地雷总数
{
f[i]=f[j]+danger[i];
next[i]=j;
}
for(int i=1;i<=n;i++)
if(sum<f[i])
{
sum=f[i];
k=i;
}
cout<<k;
k=next[k];
while(k)
{
cout<<"-"<<k;
k=next[k];
}
cout<<sum<<endl;
}