乐师理工ACM集训-最短路径

HDU2544 最短路

传送门:HDU2544 最短路

解题思路

  单源最短路径

AC代码【Dijkstra】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int MAXN = 105;
const int INF = 0x3f3f3f3f;
int n, m;
int dis[MAXN];
vector<pii> edge[MAXN];
priority_queue<pii,vector<pii>,greater<pii> > q;
void dijkstra()
{
	// 起点到所有点距离无穷大
	memset(dis,INF,sizeof(dis));
	dis[1] = 0; // 起点到自己距离为 0
	// pair的first优先级高,first存距离,second存点
	q.push(pii(0,1));
	while (!q.empty())
	{
		pii t = q.top();
		q.pop();
		int v = t.second;
		// 已经求得的距离更小,就不用操作了(懒惰删除)
		if (t.first > dis[v])
		{
			continue;
		}
		// 对邻接点进行松弛操作
		for (int i = 0; i < edge[v].size(); i++)
		{
			int p = edge[v][i].first;
			int w = edge[v][i].second;
			if (dis[p] > dis[v] + w)
			{
				dis[p] = dis[v] + w;
				q.push(pii(dis[p], p));
			}
			
		}
	}	
	// 清空图
	for (int i = 0; i <= n; i++)
	{
		edge[i].clear();
	}
}
int main()
{
	int a, b, c;
	while (scanf("%d%d",&n, &m) && n)
	{
		while (m--)
		{
			scanf("%d%d%d",&a, &b, &c);
			edge[a].push_back(pii(b,c));
			edge[b].push_back(pii(a,c));
		}
		dijkstra();
		printf("%d\n",dis[n]);
	}
	return 0;
}

HDU2066 一个人的旅行

传送门:HDU2066 一个人的旅行

解题思路

  可以假设草儿家在0号城市,她到相邻城市的距离为0(或者说直接从相邻城市出发)。跑Dijkstra即可。

AC代码【Dijkstra】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int MAXN = 1005;
const int INF = 0x3f3f3f3f;
int T, S, D;
int dis[MAXN],x[MAXN];
vector<pii> edge[MAXN];
priority_queue<pii,vector<pii>,greater<pii> > q;
void dijkstra()
{
	//dis[0] = 0;
	//q.push(pii(0,0));
	
	// 直接从几个相邻城市出发
	while (!q.empty())
	{
		pii t = q.top();
		q.pop();
		int v = t.second;
		if (t.first > dis[v])
		{
			continue;
		}
		for (int i = 0; i < edge[v].size(); i++)
		{
			int p = edge[v][i].first;
			int w = edge[v][i].second;
			if (dis[p] > dis[v] + w)
			{
				dis[p] = dis[v] + w;
				q.push(pii(dis[p], p));
			}
			
		}
	}	
	for (int i = 0; i < MAXN; i++)
	{
		edge[i].clear();
	}
}
int main()
{
	int a, b, c;
	while (~scanf("%d%d%d",&T, &S, &D))
	{
		while (T--)
		{
			scanf("%d%d%d",&a, &b, &c);
			edge[a].push_back(pii(b,c));
			edge[b].push_back(pii(a,c));
		}
		memset(dis,INF,sizeof(dis));
		int ans = INF, nc;
		// S 个邻接城市可直达
		for (int i = 0; i < S; i++)
		{
			scanf("%d",&nc);
			dis[nc] = 0; // 到邻接城市距离为 0
			q.push(pii(0,nc));
		}
		dijkstra();
		for (int i = 0; i < D; i++)
		{
			scanf("%d",&nc);
			// 找想去的 D 个城市中最短的时间
			ans = min(ans,dis[nc]);
		}
		printf("%d\n",ans);
	}
	return 0;
}

HDU1874 畅通工程续

传送门:HDU1874 畅通工程续

解题思路

  求起点到终点距离,单源最短路径。

AC代码【Dijkstra】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int MAXN = 105;
const int INF = 0x3f3f3f3f;
int n, m;
int dis[MAXN];
vector<pii> edge[MAXN];
priority_queue<pii,vector<pii>,greater<pii> > q;
void dijkstra(int strat)
{
	memset(dis,INF,sizeof(dis));
	dis[strat] = 0;
	q.push(pii(0,strat));
	while (!q.empty())
	{
		pii t = q.top();
		q.pop();
		int v = t.second;
		if (t.first > dis[v])
		{
			continue;
		}
		for (int i = 0; i < edge[v].size(); i++)
		{
			int p = edge[v][i].first;
			int w = edge[v][i].second;
			if (dis[p] > dis[v] + w)
			{
				dis[p] = dis[v] + w;
				q.push(pii(dis[p], p));
			}
			
		}
	}	
	for (int i = 0; i <= n; i++)
	{
		edge[i].clear();
	}
}
int main()
{
	int a, b, c;
	while (~scanf("%d%d",&n, &m))
	{
		while (m--)
		{
			scanf("%d%d%d",&a, &b, &c);
			edge[a].push_back(pii(b,c));
			edge[b].push_back(pii(a,c));
		}
		int strat, stop;
		scanf("%d%d",&strat, &stop);
		dijkstra(strat);
		printf("%d\n",dis[stop] == INF ? -1:dis[stop]);
	}
	return 0;
}

HDU2112 HDU Today

传送门:HDU2112 HDU Today

解题思路

  用map对城市进行唯一编号(将城市名与编号映射起来),然后建立无向图跑最短路即可。

注意事项

1、道路是双向可达的
2、起点和终点可能相同

AC代码1【Floyd】

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;
typedef pair<int,int> pii;
const int MAXN = 1005;
const int INF = 0x3f3f3f3f;
int n, ind = 0;
int dis[MAXN];
vector<pii> edge[MAXN];
int g[200][200];
map<string,int> mp;
priority_queue<pii,vector<pii>,greater<pii> > q;
void init()
{
	for (int i = 0; i < 200; i++)
	{
		for (int j = 0; j < 200; j++)
		{
			g[i][j] = INF;
		}
		g[i][i] = 0;
	}
	ind = 0;
	mp.clear();
}
void floyd()
{
	for (int i = 0; i < ind; i++)
	{
		for (int j = 0; j < ind; j++)
		{
			for (int k = 0; k < ind; k++)
			{
				g[j][k] = min(g[j][k], g[j][i] + g[i][k]);
			}
		}
	}
}
int main()
{
	IOS
	string strat, stop;
	string a, b;
	int x, y, c;
	while (cin >> n && n!= -1)
	{
		init();
		cin >> strat >> stop;
		mp[strat] = ind++;
		if (!mp.count(stop))
		{
			mp[stop] = ind++;
		}
		while (n--)
		{
			cin >> a >> b >> c;
			if (!mp.count(a))
			{
				mp[a] = ind++;
			}
			if (!mp.count(b))
			{
				mp[b] = ind++;
			}
			x = mp[a], y = mp[b];
			// 双向道路且若有重复的道路要取距离小的
			g[x][y] = g[y][x] = min(g[y][x], c);
		}
		floyd();
		x = mp[strat], y = mp[stop];
		cout << (g[x][y] == INF ? -1 : g[x][y]) << "\n";
	}
	return 0;
}

AC代码2【Dijkstra】

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;
typedef pair<int,int> pii;
const int MAXN = 1005;
const int INF = 0x3f3f3f3f;
int n, ind = 0;
int dis[MAXN];
vector<pii> edge[MAXN];
map<string,int> mp;
priority_queue<pii,vector<pii>,greater<pii> > q;
void init()
{
	for (int i = 0; i < ind; i++)
	{
		edge[i].clear();
	}
	ind = 0;
	mp.clear();
}
void dijkstra(int strat)
{
	memset(dis,INF,sizeof(dis));
	dis[strat] = 0;
	q.push(pii(0,strat));
	while (!q.empty())
	{
		pii t = q.top();
		q.pop();
		int v = t.second;
		if (t.first > dis[v])
		{
			continue;
		}
		for (int i = 0; i < edge[v].size(); i++)
		{
			int p = edge[v][i].first;
			int w = edge[v][i].second;
			if (dis[p] > dis[v] + w)
			{
				dis[p] = dis[v] + w;
				q.push(pii(dis[p], p));
			}
			
		}
	}	
}
int main()
{
	IOS
	string strat, stop;
	string a, b;
	int x, y, c;
	while (cin >> n && n!= -1)
	{
		cin >> strat >> stop;
		mp[strat] = ind++;
		if (!mp.count(stop))
		{
			mp[stop] = ind++;
		}
		while (n--)
		{
			cin >> a >> b >> c;
			if (!mp.count(a))
			{
				mp[a] = ind++;
			}
			if (!mp.count(b))
			{
				mp[b] = ind++;
			}
			x = mp[a], y = mp[b];
			// 无向图
			edge[x].push_back(pii(y,c));
			edge[y].push_back(pii(x,c));
		}
		x = mp[strat], y = mp[stop];
		dijkstra(x);
		cout << (dis[y] == INF ? -1 : dis[y]) << "\n";
		init();
	}
	return 0;
}

HDU1385 Minimum Transport Cost

传送门:HDU1385 Minimum Transport Cost

题目大意

  给定一个N表示有N个城市,接下来的N行每行N个数描述了两两城市之间的路费(-1表示两个城市没有直接路径),然后给定一行N个数表示每个城市的收费。接下来会有一些询问。
  问:对于给定城市a和b,从a到b花费的最少费用为多少(费用为路费+经过城市的收费,起点和终点不收费),并给出路径。如果有相同的最短路径值,路径按字典序输出。

解题思路

  由于给定的询问城市是任意的,可以当做多源最短路处理。用Floyd计算任意两个城市之间的最短路径,并在过程中记录中转点便于后期输出路径。

AC代码【Floyd】

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long ll;
typedef pair<int,int> pii;
const int MAXN = 300;
const int INF = 0x3f3f3f3f;
int n;
int g[MAXN][MAXN],cost[MAXN],path[MAXN][MAXN];
void floyd()
{
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			for (int k = 1; k <= n; k++)
			{
				// 通过 i 城市中转的花费
				int w = g[j][i] + g[i][k] + cost[i];
				
				// 若通过 i 城市中转花费更少
				if (g[j][k] > w)
				{
					g[j][k] = w;
					// j -> k = j -> i -> k, j -> i = .....
					path[j][k] = path[j][i];
				}
				
				// 花费相同时保证路径按字典序顺序
				else if (g[j][k] == w)
				{
					path[j][k] = min(path[j][i], path[j][k]);
				}
			}
		}
	}
}
// 打印路径
void output(int s, int e)
{

	printf("Path: ");
    int temp = s;
    while(temp != e)
    {
        printf("%d-->",temp);
        temp = path[temp][e];
    }
    printf("%d\n",e);
}
int main()
{
	int a, b, c;
	while(~scanf("%d",&n) && n)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				scanf("%d",&c);
				path[i][j] = j; // 初始化
				g[i][j] = (c == -1 ? INF:c); 
			}
		}
		for (int i = 1; i <= n; i++)
		{
			scanf("%d",&cost[i]);
		}
		floyd();
		while (scanf("%d%d",&a, &b) && a != -1)
		{
			printf("From %d to %d :\n",a, b);
			output(a,b);
			printf("Total cost : %d\n\n",g[a][b]);
		}
	}
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值