SGU 4444 Travel(最短路+bfs)



题意:给定一个完全图,其中有两种边,长度为a(不超过5e5)或长度为b(剩下的),求有1~n的最短路径(数据范围1e5)。

思路:这题的答案显然分为两种情况,第一种1到n的边长为b,这时我们要求长为a的这些边从1到n的最短路,因为边长都相同,一次bfs即可。

第二种情况是1到n的边长为a,此时我们要求长为b的这些边从1到n的最短路,因为边数太多,直接bfs肯定t,

考虑用一个set维护当前剩余的未到达点,每次将set中的长为a的边到达的点删去,然后bfs即可,这样做保证了每个点只被访问一次,时间复杂度为O(n*logn)。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int MAXN = 100100;
const int INF = 0x3f3f3f3f;
int n, m, a, b;
int dist[MAXN];
bool vis[MAXN];
struct Edge {
    int to,next;
} edge[MAXN*10];
int head[MAXN], tot;
void init() {
    tot = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u, int v) {
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
LL bfs1() {
	queue<int> q;
	memset(vis, 0, sizeof(vis));
	q.push(1);
	vis[1] = 1;
	while(!q.empty() && !vis[n]) {
		int t = q.front(); q.pop();
		for(int i = head[t]; i != -1; i = edge[i].next) {
			int u = edge[i].to;
			if(vis[u]) continue;
			dist[u] = dist[t] + 1;
			vis[u] = 1;
			q.push(u);
		}
	}
	if(!vis[n]) return INF;
	else return (LL)dist[n]*a;
}
LL bfs2() {
	set<int> last;
	for(int i = 2; i <= n; i++) last.insert(i);
	queue<int> q;
	memset(vis, 0, sizeof(vis));
	q.push(1);
	vis[1] = 1;
	while(!q.empty() && !vis[n]) {
		int t = q.front(); q.pop();
		set<int> tmp;
		for(int i = head[t]; i != -1; i = edge[i].next) {
			int u = edge[i].to;
			if(vis[u]) continue;
			last.erase(u);
			tmp.insert(u);
		}
		for(set<int>::iterator it = last.begin(); it != last.end(); it++) {
			int u = *it;
			dist[u] = dist[t] + 1;
			vis[u] = 1;
			q.push(u);
		}
		last = tmp;
	}
	if(!vis[n]) return INF;
	else return (LL)dist[n]*b;
}
int main() {
    //freopen("input.txt", "r", stdin);
	while(scanf("%d%d%d%d", &n, &m, &a, &b) == 4) {
		init();
		bool tag = 0;
		for(int i = 1, u, v; i <= m; i++) {
			scanf("%d%d", &u, &v);
			addedge(u, v);
			addedge(v, u);
			if(u==1&&v==n || u==n&&v==1) tag = 1;
		}
		LL ans;
		if(tag) ans = min((LL)a, bfs2());
		else ans = min((LL)b, bfs1());
		cout << ans << endl;
	}
    return 0;
}


















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值