【A - Til the Cows Come Home】

80 篇文章 0 订阅
80 篇文章 0 订阅
写在前面的话:
  1. 接下来是Kuangbin的专题二最短路。朴素的Dijkstra只写这一次,以后不出意外都默认是堆优化(当然是正确的堆优化啦)。
  2. 这里首次提出点态的概念,目的是防止大家混淆,点态一般是指所定义的结构体,如本题中包含 iddis 两个元素。点态可能有多个,点只能有一个

思路:

  • 邻接矩阵存图无向正权图,求解最短路。
  • Dijkstra
  • 下面依次是朴素,虚假堆优化,弱智堆优化算法,和正确的堆优化算法(…)。
  • 可是,虚假的堆优化和正确的堆优化时间是一样的(…)。
    1. 朴素:查找最短距离点,vis置true,松弛。
    2. 虚假:您不用看了,使用点并扔掉,vis置true,松弛顺便找到下一个点,实际上从头到尾队列里都只有一个点(…)。至于为什么能够优化一些些,我想是把查找和松弛合并了的缘故。
    3. 弱智:所有用到的点进入优先队列,然后每次更新都会扔掉很多点,您也不用看了,纯粹是我瞎想出来的副产品。
    4. 真正:把每次松弛的点都加入队列,然后加入关键的一行判断(如果目前弹出的点态,在入队之后被别的点松驰过,就舍弃这个点态,而应当使用的点态在其出现后也已入队,所以没有问题)。

代码:

  • ·朴素:157ms 4612kB
//157ms		4612kB


#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int N,U;
int mp [maxn][maxn];
bool vis[maxn];
int dis[maxn];
int ans;

void Dijkstra(){
	dis[U] = 0;
	vis[U] = true;
	while(true){
		int temp_id;
		int temp_dis = INF;
		for(int i=1;i<=U;i++){
			if(vis[i])
				continue;
			if(temp_dis > dis[i])
				temp_dis = dis[i], temp_id = i;
		}
		if(temp_id == 1){
			ans = temp_dis; 
			return ;//true exit
		}
		vis[temp_id] = true;
		for(int i=1;i<=U;i++){
			if(vis[i])
				continue;
			dis[i] = min(dis[i] , dis[temp_id] + mp[temp_id][i]) ;
		}
	}
	//题目保证有解 
}

int main(){
	memset(mp,INF,sizeof(mp));
	for(int i=1;i<=U;i++)
		mp[i][i] = 0;
	memset(dis,INF,sizeof(dis));
	memset(vis,false,sizeof(vis));
	cin>>N>>U;
	for(int i=1;i<=N;i++){
		int x,y,w;
		cin>>x>>y>>w;
		mp[x][y] = mp[y][x] = min(mp[x][y] , w);
		if(x == U)
			dis[y] = mp[U][y];
		if(y == U)
			dis[x] = mp[U][x];
	}
	Dijkstra();
	cout<<ans<<endl;
	return 0;
}
  • 虚假的堆优化:125ms 4624kB
//125ms		4624kB


#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int N,U;
int mp[maxn][maxn];
bool vis[maxn];
int dis[maxn];
struct node{
	int id;
	int dis;
	node(int id,int dis) : id(id) , dis(dis) {} ;
	friend bool operator > (const node & a , const node & b)
	{
		return a.dis > b.dis;
	}
};
priority_queue<node , vector<node> , greater<node> > Q;
int ans;

void Init(){
	memset(mp,INF,sizeof(mp));
	for(int i=1;i<=U;i++)
		mp[i][i] = 0;
	memset(dis,INF,sizeof(dis));dis[U]=0;
	memset(vis,0,sizeof(vis));
	return ;
}

void Dijkstra(){
	Q.push(node(U,0));vis[U]=true;
	while(Q.size()){
		node cur = Q.top();Q.pop();
		if(cur.id == 1){
			ans = cur.dis;
			return ;
		}
		for(int i=1;i<=U;i++){
			if(vis[i])
				continue;
			dis[i] = min(dis[i] , dis[cur.id] + mp[cur.id][i]);
		}
		int temp_id;
		int temp_dis = INF;
		for(int i=1;i<=U;i++){
			if(vis[i])
				continue;
			if(temp_dis > dis[i])
				temp_id = i , temp_dis = dis[i];
		}
		Q.push(node(temp_id,temp_dis));vis[temp_id]=true;
	}
}

int main(){
	cin>>N>>U;
	Init();
	for(int i=1;i<=N;i++){
		int v,u,w;
		cin>>v>>u>>w;
		mp[v][u] = mp[u][v] = min(mp[u][v] , w);
	}
	Dijkstra();
	cout<<ans<<endl;
	return 0;
}
  • 弱智堆优化算法:188ms 4688kB
//188ms		4688kB


#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int N,U;
int mp[maxn][maxn];
bool vis[maxn];
int dis[maxn];
struct node{
	int id;
	int dis;
	node(int id,int dis) : id(id) , dis(dis) {} ;
	friend bool operator > (const node & a , const node & b)
	{
		return a.dis > b.dis;
	}
};
priority_queue<node , vector<node> , greater<node> > Q;
int ans;

void Init(){
	memset(mp,INF,sizeof(mp));
	for(int i=1;i<=U;i++)
		mp[i][i] = 0;
	memset(dis,INF,sizeof(dis));
	memset(vis,0,sizeof(vis));
	return ;
}

void Dijkstra(){
	dis[U] = 0;
	for(int i=1;i<U;i++)
		Q.push(node(i,INF));
	Q.push(node(U,0));
	while(Q.size()){
		node cur = Q.top();Q.pop();
		if(cur.dis != dis[cur.id])
			continue;
		vis[cur.id] = true;
		if(cur.id == 1){
			ans = cur.dis;
			return ;
		}
		for(int i=1;i<=U;i++){
			if(vis[i])
				continue;
			if(dis[i] > dis[cur.id] + mp[cur.id][i])
				dis[i] = dis[cur.id] + mp[cur.id][i] , Q.push(node(i , dis[i]));
		}
	}
}

int main(){
	cin>>N>>U;
	Init();
	for(int i=1;i<=N;i++){
		int v,u,w;
		cin>>v>>u>>w;
		mp[v][u] = mp[u][v] = min(mp[u][v] , w);
	}
	Dijkstra();
	cout<<ans<<endl;
	return 0;
}
  • 正确的堆优化:125ms 4636kB
//125ms		4636kB 


#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int N,U;
int mp[maxn][maxn];
bool vis[maxn];
int dis[maxn];
struct node{
	int id;
	int dis;
	node(int id,int dis) : id(id) , dis(dis) {} ;
	friend bool operator > (const node & a , const node & b)
	{
		return a.dis > b.dis;
	}
};
priority_queue<node , vector<node> , greater<node> > Q;
int ans;

void Init(){
	memset(mp,INF,sizeof(mp));
	for(int i=1;i<=U;i++)
		mp[i][i] = 0;
	memset(dis,INF,sizeof(dis));dis[U]=0;
	memset(vis,0,sizeof(vis));
	return ;
}

void Dijkstra(){
	Q.push(node(U,0));vis[U]=true;
	while(Q.size()){
		node cur = Q.top();Q.pop();vis[cur.id]=true;
		if(cur.id == 1){
			ans = cur.dis;
			return ;
		}
		if(cur.dis != dis[cur.id])
			continue;
		//注意:如果不加上面的一行判断,就根本没有优化,时间和朴素一样,但是因为不会成功松弛,所以不会产生错解。 
		//因为对那些 id 与本点态相同的点态来说,新的点态一定排在本点态前面(dis小)
		//对 id 不同且 dis 比它大的点态会排在它后面,但是因为它们已经被更优的本点松弛过了,所以本点态变得毫无用处。
		//因为本写法中每次拿出点的时候都置true,所以只好这样判断。
		//其实不应该这么写,我更提倡下一篇BLOG中的写法
		for(int i=1;i<=U;i++){
			if(vis[i])
				continue;
			if(dis[i] > dis[cur.id] + mp[cur.id][i]){
				dis[i] = dis[cur.id] + mp[cur.id][i];
				Q.push(node(i , dis[i]));
			}
		}
	}
}

int main(){
	cin>>N>>U;
	Init();
	for(int i=1;i<=N;i++){
		int v,u,w;
		cin>>v>>u>>w;
		mp[v][u] = mp[u][v] = min(mp[u][v] , w);
	}
	Dijkstra();
	cout<<ans<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值