您的位置:首页 > 编程语言 > C语言/C++

CCF交通规划C++版源码分享(201612-4)

2016-12-14 17:22 381 查看
问题描述

  G国国王来中国参观后,被中国的高速铁路深深的震撼,决定为自己的国家也建设一个高速铁路系统。

  建设高速铁路投入非常大,为了节约建设成本,G国国王决定不新建铁路,而是将已有的铁路改造成高速铁路。现在,请你为G国国王提供一个方案,将现有的一部分铁路改造成高速铁路,使得任何两个城市间都可以通过高速铁路到达,而且从所有城市乘坐高速铁路到首都的最短路程和原来一样长。请你告诉G国国王在这些条件下最少要改造多长的铁路。

输入格式

  输入的第一行包含两个整数n, m,分别表示G国城市的数量和城市间铁路的数量。所有的城市由1到n编号,首都为1号。

  接下来m行,每行三个整数a, b, c,表示城市a和城市b之间有一条长度为c的双向铁路。这条铁路不会经过a和b以外的城市。

输出格式

  输出一行,表示在满足条件的情况下最少要改造的铁路长度。

样例输入

4 5

1 2 4

1 3 5

2 3 2

2 4 3

3 4 2

样例输出

11

评测用例规模与约定

  对于20%的评测用例,1 ≤ n ≤ 10,1 ≤ m ≤ 50;

  对于50%的评测用例,1 ≤ n ≤ 100,1 ≤ m ≤ 5000;

  对于80%的评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 50000;

  对于100%的评测用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000,1 ≤ a, b ≤ n,1 ≤ c ≤ 1000。输入保证每个城市都可以通过铁路达到首都。

这是在上一篇《交通规划》的基础上改进的,主要是使用了邻接表的图存储结构,避免的内存超限制,主要思想还是迪杰斯特拉算法,但是有所改变(就是两个节点的距离源节点距离相等时的情况),具体见代码的中的注释。
截至目前,程序在运行时还是会出现 堆错误,但是仍然能够通过所有测试,因为错误是在得到结果之后,算是小幸运吧。
关于这个错误,我也是百思不得其解,已经把问题定位到了邻接链表的内存释放,最初我是定义了顶点类的析构函数,在该析构函数内释放了该顶点的邻接链表内存,(我以为)当图的生命期结束时,图的顶点生命期也会结束,这是也就自动调用了顶点类的析构函数,释放邻接链表内存,但是这样总是会出现“.....exe已停止工作”(在我的所有测试都是这样),提交测试也不通过(关于我这种理解,有兴趣的伙伴可以交流交流)。接下来,我直接定义了图类的析构函数,在该析构函数内遍历所有顶点,逐个释放邻接表内存,改程序能够准确无误通过题目给的测试样例.于是提交代码,ok.
注意:如果直接使用代码中的测试矩阵,则需要将m--和n--注释掉。
以上遗留的问题,欢迎交流,下面附上代码:


#include <iostream>
#include<string>
#include<vector>
#include <stdint.h>
using namespace std;

#define max 10000
#define infinity 65535
// int weightall[16][3] = { { 0, 1, 1 },
// { 0, 2, 5 },
// { 1, 2, 3 },
// { 1, 3, 5 },
// { 1, 4, 5 },
// { 2, 4, 1 },
// { 2, 5, 7 },
// { 3, 4, 2 },
// { 3, 6, 3 },
// { 4, 6, 6 },
// { 4, 7, 9 },
// { 4, 5, 3 },
// { 5, 7, 5 },
// { 6, 7, 2 },
// { 6, 8, 7 },
// { 7, 8, 4 }
//  };
class edgenode
{
public:
int adjvex;//邻接点下标
int weight;//当前路径长度
edgenode *next;
edgenode(int Adjvex, int Weight) :adjvex(Adjvex), weight(Weight)
{
next = NULL;
}
};

class vertexNode
{
public:
int sumweight;//到源节点的距离
int thisweight;//到前驱节点的距离
int lastVertex;//前驱节点下标
bool isShortest;//是否已纳入最短路径
edgenode *firstEdge;//邻接表头指针

//  ~vertexNode()
//  {
//      edgenode *node = firstEdge, *Next=NULL;
//      while (node!=NULL)
//      {
// //           last = node;
// //           node = node->next;
// //           delete last;
//          Next = node->next;
//          delete node;
//          node = Next;
//      }
//  }
};
class graph
{
public:
int numVertexes, numEdges;//节点和边数量
int sum;//改造路径长度
int original;//源节点下标
vertexNode vertexes[max];

void createG();
/*void miniTree();*/
void dijkstraPath(int v0);
~graph();
};

void graph::createG()
{
int i, m, n, weight;
sum = 0;
original = 0;
cin >> numVertexes >> numEdges;
//  numVertexes = 9;
//  numEdges = 16;
//构造顶点
for (i = 0; i < numVertexes; i++)
{
vertexes[i].isShortest = false;
vertexes[i].firstEdge = NULL;
vertexes[i].sumweight = infinity;
vertexes[i].thisweight = infinity;//用于处理当前节点距离源节点距离不变但是可以减少改造距离的情况
vertexes[i].lastVertex = 0;
}

//构造边
for (i = 0; i < numEdges; i++)
{
cin >> m >> n >> weight;
m--;//减一是因为输入编号是从1开始的,而编号从0开始处理比较方便
n--;
//      m = weightall[i][0];
//      n = weightall[i][1];
//      weight = weightall[i][2];
edgenode *temEdge_m = new edgenode(n,weight);
temEdge_m->next = vertexes[m].firstEdge;
vertexes[m].firstEdge = temEdge_m;

edgenode *temEdge_n = new edgenode(m,weight);
temEdge_n->next = vertexes
.firstEdge;
vertexes
.firstEdge = temEdge_n;
}
}

graph::~graph()
{
for (int i = 0; i < numVertexes;i++)
{
edgenode *node = vertexes[i].firstEdge, *Next = NULL;
while (node != NULL)
{
//          last = node;
//          node = node->next;
//          delete last;
Next = node->next;
delete node;
node = Next;
}
}
}
void graph::dijkstraPath(int v0)
{
original = v0;
int min, minIndex;
//将源节点直接加入最短路径
vertexes[original].isShortest = true;
vertexes[original].sumweight = 0;
vertexes[original].thisweight = 0;

edgenode* temNode = vertexes[original].firstEdge;//初始化所有节点到 源节点 的距离以及对应下标
while (temNode!=NULL)
{
vertexes[temNode->adjvex].sumweight = temNode->weight;
vertexes[temNode->adjvex].thisweight = temNode->weight;
vertexes[temNode->adjvex].lastVertex = original;
temNode = temNode->next;
}

for (int v = 0; v < numVertexes; v++)
{
if (v == original)//源节点则跳出
{
continue;
}
min = infinity;
for (int w = 0; w < numVertexes; w++)//找最短距离和下标~sumweight
{
if (!vertexes[w].isShortest && min >vertexes[w].sumweight)
{
min = vertexes[w].sumweight;
minIndex = w;
}
//          else if (!vertexes[w].isShortest && min != infinity && min == vertexes[w].sumweight && vertexes[minIndex].thisweight>vertexes[w].thisweight)
//          {
//              minIndex = w;//因为min不变,所以不更新。(当前立刻马上就要加入最短路径的点)
//          }
}
sum = sum + vertexes[minIndex].thisweight;//记录改造距离
//cout << "当前距离sum=" << sum << "      " << "当前节点" << minIndex << endl;
vertexes[minIndex].isShortest = true;//将距离最近的节点加入最短路径

temNode = vertexes[minIndex].firstEdge;
while (temNode!=NULL)
{
if(!vertexes[temNode->adjvex].isShortest && vertexes[temNode->adjvex].sumweight > min + temNode->weight)//最短距离更短,必须更新
{
vertexes[temNode->adjvex].sumweight = min + temNode->weight;
vertexes[temNode->adjvex].lastVertex = minIndex;
vertexes[temNode->adjvex].thisweight = temNode->weight;//更新到前驱节点的距离
}
else if(vertexes[temNode->adjvex].sumweight == min + temNode->weight &&//(未加入最短路径的点)当前最短距离不变,则改造的路径距离可以更短时也要更新
vertexes[temNode->adjvex].thisweight>temNode->weight && !vertexes[temNode->adjvex].isShortest)
{
vertexes[temNode->adjvex].lastVertex = minIndex;
vertexes[temNode->adjvex].thisweight = temNode->weight;//更新到前驱节点的距离
}

temNode = temNode->next;
}
}
}

int main()
{
graph G;
G.createG();
//G.miniTree();//只保证改造路径最短,即最小生成树
G.dijkstraPath(0);//单源最短路径,且改造距离最短,比原始的dijkstra增加了最短路径距离不变的情况
cout << G.sum << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ccf c++ dijkstra