算法第三章作业
动态规划之挖地雷
在一个地图上有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
1 #include <iostream> 2 #include <limits.h>//整型最大最小值的头文件 3 4 using namespace std; 5 6 const int maxn=210; 7 int dp[maxn]={};//dp[i]:代表从某点出发到终点所挖的最大地雷数 8 int G[maxn][maxn]={};//记录两个地窖是否通路 9 int p[maxn]={};//记录最大地雷数路径 10 11 int main() 12 { 13 int n; 14 scanf("%d",&n); 15 for(int j=1;j<=n;j++){ 16 scanf("%d",&dp[j]); 17 } 18 19 int a,b; 20 while(true){ 21 scanf("%d%d",&a ,&b); 22 if(!a && !b) break; 23 G[a][b]=1; 24 } 25 26 int max=INT_MIN; 27 int find,temp; 28 for(int i=n-1;i>0;i--){ 29 //从倒数第二个地窖开始往前算与它相连地窖的最大地雷数 30 temp=0; 31 for(int j=i+1;j<=n;j++){ 32 //找到该地窖与直接连接的某个地雷数最大的地窖 33 if(G[i][j]==1){ 34 if(dp[j]>temp){ 35 temp=dp[j]; 36 p[i]=j;//j地窖是i的最优路径 37 } 38 } 39 } 40 //更新使得dp[i]最大:也就是从i出发到结尾的最大地雷数是dp[i] 41 dp[i]+=temp; 42 if(dp[i]>max){ 43 max=dp[i]; 44 /*由于最大不定是从1开始挖的,所以需要找出最大值*/ 45 find=i; 46 } 47 } 48 //打印路径 49 printf("%d",find); 50 while(p[find]!=0){ 51 printf("-%d",p[find]); 52 find=p[find]; 53 } 54 //打印最大值 55 printf("\n%d\n",max); 56 return 0; 57 }
1. 任选作业题”单调递增最长子序列“、”挖地雷“、”编辑距离问题“中的一题分析
首先算出从每一个地窖出发到终点所能挖的最大地雷数,此时动态规划思路要从后面往前面算,因为前面的最大地雷数是取决于与它相连的拥有最大地雷数的地窖。
于是只要计算出与其相连的地窖中,那个的地雷数最大即可。
1.1 根据最优子结构性质,列出递归方程式,
dp[i] = dp[i] + max{ (i<j<=n && G[i][j]==1)dp[j] }; 最终的 max = max{(1<=i<=n)dp[i]};
1.2 给出填表法中表的维度、填表范围和填表顺序。
填表的维度是一维;填表范围是整个数组(1~N);填表顺序是从后往前填
1.3 分析该算法的时间和空间复杂度
时间复杂度:双重循环不难得O(n^2) ;空间复杂度:由于使用了二维数组储存了矩阵所以复杂度是O(n^2);
2. 你对动态规划算法的理解
理解:将求最优解的问题划为一些子问题,子问题的最优解的综合即为原问题的最优解,一般是根据规律找出递归方程并求解。
3. 说明结对编程情况
变的有点难突破,虽然结果是算出来了,但是有些曲折,要花很长时间才能做出来。