CG平台 OJ 3069 网红重庆1
题目:
CG平台:10.1.74.121
【问题描述】
网红城市——重庆,堪称一座8D的魔幻大都市,明明(不要问我明明是谁?)在一楼上的电梯,到了11楼出电梯又是一楼。
假设重庆有N个地点,给出各个地点的海拔高度,各个地点之间可能有双向的路径连接,或者单向的路径连接。有一个外地人来重庆,要从地点C到D,但他对爬坡下坎很不习惯,请帮他在从C到D所有路径中,找一条海拔变化(海拔降低或升高都视为正的值)最小的路径,即组成路径的各条直接路径海拔变化的总和最小。
【输入形式】
输入文件包含多个测试数据。每个测试数据第1行是两个整数N和M,N表示地点的数目,5≤N≤50,地点的序号从1开始计起,M表示这N个地点之间直接路径的数目,对任意两个地点A、B,A和B之间有一条双向直接路径、从A到B有一条单向直接路径、从B到A有一条单向直接路径,这3种情形最多只出现一种情形,测试数据保证这N个地点之间是互相可达的(再啷个爬坡下坎,总还是走得到的);第2行有N个整数,表示这N个地点的海拔高度,范围在[100, 1000],可能存在相同海拔高度的地点;接下来有M行,描述了M条直接路径,格式为“1 A B”或“2 A B”,前者表示从地点A到地点B的一条单向直接路径,后者表示地点A和B之间的一条双向直接路径,A和B为地点的序号,A≠B;每个测试数据的最后一行为两个整数C和D,表示那个外地人要从地点C到D,C和D为地点的序号,C≠D。测试数据保证地点序号都是有效的。
输入文件最后一行为0 0,代表输入结束。
【输出形式】
对每个测试数据,输出占一行,为求得的从地点C到D的各条路径中海拔变化总和的最小值。
【样例输入】
5 5
100 160 230 450 120
2 1 2
1 1 5
2 2 5
2 3 4
2 4 5
1 3
0 0
【样例输出】
570
【样例说明】
【评分标准】
解题思路:
1.从题目可以看出结点最大数为50,定义一个全局变量L=60;main中开二维数组n[L][L],第一个下标表示起点,第二个下标表示终点,元素值表示起点到终点的最短路径。(下标为1~N)例如:N=4,开如下数组,每一行表示一个结点到其他结点的最短路径,比如n[1][2]表示结点1到结点2的最短路径为20
2.初始化数组n,结点自身的距离为0,到其他结点为Max,(Max定义为全局变量);再根据输入的各点海拔值,及各点之间的路径,将海拔差填充进数组n;例如结点1和结点2海拔差为20,结点1和结点2单向路径,1–>2,所以n[1][2]为20,如果为双向路径,n[2][1]也要填充20。
3.利用最短距离算法,计算出出发点到其他结点的最小海拔变化。
最短路径:
思想:
从出发点到其他的结点距离,每次总能找到一个最小值M的路径,这个距离必定是出发点到该结点的最短路径M。因为该路径的值M,小于出发点到其他结点的路径值N,M<N,再从其他结点到该结点,距离只会增大,所以M是出发点到该结点的最短路径。
1.出发点直接能到达的点的距离已经填充,不能到达的距离为max
2.建立一个数组 succ,用来判定已经求出的距离出发点最短路径的结点,已求出为true
3.进入循环,每次循环求出出发点到一个结点的最短路径,循环次数为未求出最短路径的结点数
4.首先求出此次循环中succ为false的结点中最短的路径,获取其结点编号index,和该最短路径值(在此题中,如果index等于目的地的编号,则终止循环,直接输出最短路径)
5.依次判断succ中为false的结点中的路径与出发点到index加上index到该结点之和的最小值,将两者最小值进行填充
6.循环至succ所有值为true
遇到的问题
1.最大的表示
查询资料后,定义全局变量Max=0x3f3f3f3f。该数为int型变量最大值;
2.OJ的文件循环输入,输入至 0 0 结束,需要在外部定义N、M,输入N、M值,再用while循环判断这两个值不为0进入循环,同时还需要在循环末尾再次输入N、M,不然陷入死循环;!!!!
注意事项
1.以后做题看清数组大小,将数组大小直接定义成题目给定的最大+10,定义成全局变量N。在开数组时直接使用该变量开数组,循环数组时使用输入的数组大小n;
2.调用cmath库使用绝对值,整型为abs(),浮点型为fabs();
Time Limit Error 常见原因
1.是死循环。for,while等等没有循环结束的条件,导致死循环 ;
2.代码里有太多没有必要的循环。每一个循坏都需要一段时间,循环过多,运行时间会加长。
3.你用的方法太复杂。每个题在提交时都会显示运行了多少时间,如果方法复杂,就会超出系统给出的时间,但这并不代表你的代码是错的。
Runtime Error常见原因
1、数组开得太小了,导致访问到了不该访问的内存区域
2、发生除零错误
3、大数组定义在函数内,导致程序栈区耗尽
4、指针用错了,导致访问到不该访问的内存区域
5、还有可能是程序抛出了未接收的异常
---------------------------待补充-------------------------------
代码
```cpp
#include<iostream>
using namespace std;
#include<cmath>
const int Max = 0x3f3f3f3f;
const int L=60;
int main()
{
int N,M;
cin>>N>>M;
while(N!=0 && M!=0){
int high[L]; //海拔数组
int n[L][L]; //结点数组
//处理结点数组
for(int i =1;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
n[i][j] = Max;
}
n[i][i] = 0;
}
//输入海拔
for(int i=1;i<=N;i++)
cin>>high[i];
//输入路径
for(int i=1;i<=M;i++){
int d=0;
cin>>d;
int x,y;
cin>>x>>y;
if(d == 1){
n[x][y] = abs(high[x]-high[y]);
}else
{
n[x][y] = abs(high[x]-high[y]);
n[y][x] = abs(high[x]-high[y]);
}
}
//输入起点和终点
int first,last;
cin>>first>>last;
//辅助判断数组
int succ[L]; //true = 1 ; false = 0;
for(int i=1;i<=N;i++)
succ[i] = 0;
//起点设为1
succ[first]=1;
for(int i=1;i<=N-2;i++)
{
//求出此次循环中的最短路径和结点下标
int minins = Max;
int index ;
for(int j=1;j<=N;j++)
{
if(succ[j]!=1 && n[first][j]<minins)
{
minins = n[first][j];
index = j;
}
}
//如果该结点为终点,则终止循环
if(index == last) break;
//修改辅助数组,表示已求出该结点的最短路径
succ[index] = 1;
//5.依次判断succ中为false的结点中的路径与出发点到index加上index到该结点之和的最小值,将两者最小值进行填充
for(int j=1;j<=N;j++)
{
if(succ[j] !=1 && (minins+n[index][j])<n[first][j]){
n[first][j] = minins+n[index][j];
}
}
}
cout<<n[first][last]<<endl;
cin>>N>>M;
}
}