【C++】CCF 201703-4 地铁修建 【从80分到100分的优化过程】

#include <bits/stdc++.h>
using namespace std;
const int MAX_EDGE = 200005;
const int MAX_VERTICES = 100005;
struct Edge{
	int v, len, last;
} edge[2 * MAX_EDGE];
 //开始是80分,后来改了一下就对了,原因是无向图的边集上限应该是题目给出上限的两倍而不是相同
bool vst[MAX_VERTICES];
int latest_edge_of_u[MAX_VERTICES];
int dis[MAX_VERTICES];
int eid, nv, ne;
void init(){
	for(int i = 0 ; i < MAX_VERTICES ; i++){
		vst[i] = false;
		dis[i] = 200000000;
		latest_edge_of_u[i] = -1;
	}
	eid = 0;
}
void insert(int w, int u, int v){
	edge[eid].v = v;
	edge[eid].len = w;
	edge[eid].last = latest_edge_of_u[u];
	latest_edge_of_u[u] = eid++;
	edge[eid].v = u;
	edge[eid].len = w;
	edge[eid].last = latest_edge_of_u[v];
	latest_edge_of_u[v] = eid++; 
}
int find_min(){
	int min_weight = 0, min_index = 0;
	for(int i = 1 ; i < nv + 1 ; i++){
		if(!vst[i]){
			min_weight = dis[i];
			min_index = i;
			break;
		}
	}
	for(int i = 1 ; i < nv + 1 ; i++){
		if(!vst[i] && dis[i] < min_weight){
			min_weight = dis[i];
			min_index = i;
		}
	}
	vst[min_index] = true; //这里易错 
	return min_index;
}
void dijkstra(int start){
	dis[start] = 0;
	for(int i = 1 ; i < nv + 1 ; i++){
		int u = find_min();
		for(eid = latest_edge_of_u[u] ; eid != -1 ; eid = edge[eid].last){
			if(dis[edge[eid].v] > dis[u] + edge[eid].len){ //说明需要更新值 
				if(edge[eid].len <= dis[u]){
					dis[edge[eid].v] = dis[u];
				} 
				else dis[edge[eid].v] = edge[eid].len;
			}
		}
	}
}
int main(){
	cin >> nv >> ne;
	init();
	int a, b, c;
	for(int i = 0 ; i < ne ; i++){
		cin >> a >> b >> c;
		insert(c, a, b);
	} 
	dijkstra(1);
	cout << dis[nv];
	return 0;
}

问题描述

  甲市有Ñ个交通枢纽,其中1号和Ñ号非常重要,为了加强运输能力,A市决定在1号到Ñ号枢纽间修建一条地铁。
  地铁由很多段隧道组成,每段隧道连接两个交通枢纽。经过勘探,有米段隧道作为候选,两个交通枢纽之间最多只有一条候选的隧道,没有隧道两端连接着同一个交通枢纽。
  现在有ñ家隧道施工的公司,每段候选的隧道只能由一个公司施工,每家公司施工需要的天数一致。而每家公司最多只能修建一条候选隧道。所有公司同时开始施工。
  作为项目负责人,你获得了候选隧道的信息,现在你可以按自己的想法选择一部分隧道进行施工,请问修建整条地铁最少需要多少天。

输入格式

  输入的第一行包含两个整数nm,用一个空格分隔,分别表示交通枢纽的数量和候选隧道的数量。
  第2行到第m +1行,每行包含三个整数abc,表示枢纽a和枢纽b之间可以修建一条隧道,需要的时间为c天。

输出格式

  输出一个整数,修建整条地铁线路最少需要的天数。

样例输入

6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6

样例输出

6

样例说明

  可以修建的线路有两种。
  第一种经过的枢纽依次为1,2,3,6,所需要的时间分别是4,4,7,则整条地铁线需要7天修完;
  第二种经过的枢纽依次为1,4,5,6,所需要的时间分别是2,5,6,则整条地铁线需要6天修完。
  第二种方案所用的天数更少。

评测用例规模与约定

  对于20%的评测用例,1≤ Ñ ≤10,1≤ ≤20;
  对于40%的评测用例,1≤ Ñ ≤100,1≤ ≤1000;
  对于60%的评测用例,1≤ Ñ ≤1000 ,1≤ ≤10000,1≤ ç ≤1000;
  对于80%的评测用例,1≤ ñ ≤10000,1≤ ≤100000;
  对于100%的评测用例,1≤ ñ ≤100000,1≤ ≤200000 ,1≤ 一个bñ,1个≤ ç ≤1000000

  所有评测用例保证在所有候选隧道都修通时1号枢纽可以通过隧道到达其他所有枢纽。

目前只有80分,基于迪杰斯特拉改的,松弛方法改了一下,但是提交后显示有一组运行错误,还有一种基于最小生成树写的,在下一篇小结里面

20181209在青豪犀利的目光下,一眼看出了错误,就是边集数组开小了,应该开给出的边集数组的两倍,因为每两个顶点之间有两条边,将edge[MAX_EDGE]改为edge[2* MAX_EDGE]之后就过了最后一组数据,但依然是80分,不过这次的报错原因是超时,所以有了基于shaffer提供的heap  X dijkstra 的100分解答:

//21:30
//这个代码目前有问题,需要找到一种合理有效的
//heap+dijkstra的优化算法 
//对传统的算法/V/**2的时间复杂度可以过8组数据
//然而对于这个版本的理论上应该是(/V/ + /E/ )*log /V/的复杂度却有问题 
//耗时几乎是前面基础版本的两倍,而且还有两组数据没过 
#include <bits/stdc++.h>
using namespace std;
const int MAX_EDGE = 400050;
const int MAX_VERTICES = 100005;
int nv, ne;
struct Edge{
	int v, last, w;
} edge[MAX_EDGE];
int eid, dist[MAX_VERTICES];
bool vst[MAX_VERTICES];
int latest_edge_of_u[MAX_VERTICES];
struct Dis{
	int v;
	int d;
	Dis(){}
	Dis(int v, int d){
		this->v = v;
		this->d = d; 
	} 
	bool operator < (const Dis & another) const{
		return d > another.d; 
	}
} dis[MAX_VERTICES];
void init(){
	eid = 0;
	for(int i = 0 ; i <= nv ; i++){
		vst[i] = false;
		dis[i].d = 200000000;
		dis[i].v = i;
		dist[i] = 200000000; 
		latest_edge_of_u[i] = -1;
	}
}
void insert(int w, int u, int v){
	edge[eid].v = v;
	edge[eid].w = w;
	edge[eid].last = latest_edge_of_u[u];
	latest_edge_of_u[u] = eid++;
	edge[eid].v = u;
	edge[eid].w = w;
	edge[eid].last = latest_edge_of_u[v];
	latest_edge_of_u[v] = eid++;
}
void dijkstra(int start){
	dist[start] = 0;
	dis[start].d = 0;
	priority_queue <Dis> q;
	Dis temp(start, 0);
	int temp_vertex;
	q.push(temp);
	for(int i = 1 ; i <= nv ; i++){
		do{
			temp = q.top();
			temp_vertex = temp.v;
			q.pop();
		}while(!q.empty() && vst[temp_vertex]);
		vst[temp_vertex] = true;
		for(eid = latest_edge_of_u[temp_vertex]; eid != -1; eid = edge[eid].last){
			if(dist[edge[eid].v] > max(dist[temp_vertex] , edge[eid].w)){
				dist[edge[eid].v] = max(dist[temp_vertex] , edge[eid].w);
			}
			temp.d = dist[edge[eid].v];
			temp.v = edge[eid].v;
			if(!vst[temp.v]){
				q.push(temp);
			}
		} 
	}
}
int main(){
	cin >> nv >> ne;
	init(); 
	int w, u, v;
	for(int i = 0 ; i < ne ; i++){
		cin >> u >> v >> w;
		insert(w, u, v);
	}
	dijkstra(1);
	cout << dist[nv]; 
	return 0;
}

AC,本题结束

猜你喜欢

转载自blog.csdn.net/chenhanxuan1999/article/details/84867451