算法第三章作业
1.挖地雷
在一个地图上有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
#include<cstdio>
#include<iostream>
#define N 210
#define INF 0x3f3f3f3f
using namespace std;
int b[N][N];
int a[N],p[N];
int f[N];// 表示挖到地雷最大数
void print(int k) //输出挖地雷的顺序
{
if(k == 0)
return;
print(p[k]);
if(p[k] == 0)//如果是第一个点 直接输出k 否则输出-k
cout << k;
else
cout << "-" << k;
}
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
f[i] = a[i];
}
int x,y;
while(scanf("%d%d",&x,&y) != EOF && x &&y)
b[x][y] = 1;//x->y通路
int maxx = -INF, k;
for(int i = 1; i <= n;i++)
{
for(int j = 1; j <= n;j++)
{
if(b[j][i] == 1 && f[j]+a[i] > f[i])
{
f[i] = f[j] + a[i];//保存第i个地窖起挖到的后继最大地雷数
p[i] = j; //j 地窖是i的最优路径
}
}
if(f[i] > maxx)//计算挖到最多地雷数
{
maxx = f[i];
k = i;
}
}
print(k);
cout <<endl <<maxx <<endl;
return 0;
}
1.1 根据最优子结构性质,列出递归方程式,
设m[i]从i出发挖的最多数
m[i]=max{m[j]}+a[i] i<j<=n; (i,j)∈E;
1.2 给出填表法中表的维度、填表范围和填表顺序。
维度:1维 填表范围:0<i<n 填表顺序:自左向右
1.3 分析该算法的时间和空间复杂度
O(n^2)
2.对动态规划算法的理解
动态规划思想与分治法类似,都是将问题分解为多个子问题,通过求解子问题来得到最终答案,而动态规划的优势在于,动态规划防止了子问题的重复计算,每个问题只计算一次,自底向上地求出原问题的解。
3. 说明结对编程情况
这次上机实验结对编程主要是完成了最低通行费这道题目,其实刚一开始,我和队友看到这道题目都觉得它和前面我们作业做过的数字三角形很像,所以我们想沿用那道题的代码思路,然后把它进行修改,但是我那道题是从三角形底下向上算出最大值的,而这道题已经定好了方向,只能向右向下走,所以我需要将我前面题目的代码思路顺序给倒过来,但恰巧在这个地方我卡住了。而队友她很快编出了这道题,但她用的方法有一些地方我不是很明白,比较难理解,所以她也试图改了我的代码,用比较容易懂的方法来帮助我理解,最后也成功了。在这个过程中,我觉得同伴的算法思路很清晰,一步一步很有逻辑,这一点是我值得学习的,而且结对编程也让我对题目有更深的认识和理解。