Gym 102501A Environment-Friendly Travel (二维dijkstra)

题意:平面上,要从起点到终点,中间有n个站台,站台之间有边。两点距离为欧几里得距离。每个边可以坐不同交通工具对应不同碳排放量。求起点到终点距离不超过B且碳排放量最小的路径。

题解:二维dijkstra
由于存在限制条件B,我们可以将d数组改为二维。

d [ i ] [ j ] d[i][j] d[i][j]:0点到 i 点的最小碳排放,且距离为 j 。

然后正常建边跑dijkstra即可。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
int sx, sy, tx, ty, maxdis, c[111], numc, n, x[1111], y[1111], num[1111], v[1111][1111], mod[1111][1111];
//dijkstra
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int manx = 1e3 + 5; //与n相对,对应顶点的个数
const int mamx = 5e5 + 5; //与m相对,对应边的个数

struct nod {
    
    
	ll cos;
	int v, dis;
	nod(){
    
    }
	nod(ll cos, int v, int dis):cos(cos),v(v),dis(dis){
    
    }
	bool operator<(const nod& n)const {
    
    
		if (cos == n.cos) return dis > n.dis;
		return cos > n.cos;
	}
};
priority_queue<nod> q;
struct node {
    
    
	int next, v, w;
	ll c;
}edge[mamx];  //边去mamx,其余取manx
bool vis[manx][manx];  //这里的标记数组与spfa的vis数组含义不同,这里标记是否入过队列
int head[manx];
ll d[manx][manx];
int k = 0;
int m, s, e; //s作为起点,e作为终点
void add(int u, int v, int w, ll c) {
    
     //链式前向星存图
	edge[++k].next = head[u];
	edge[k].v = v;
	edge[k].w = w;
	edge[k].c = c;
	head[u] = k;
}
void dijkstra() {
    
    
	for (int i = 0; i <= n + 1; i++) {
    
      //初始化vis d 数组
		for (int j = 0; j <= maxdis; j++) {
    
    
			d[i][j] = inf;
		}
	}
	d[s][0] = 0; //s作为起点
	q.push(nod(0, s, 0));
	while (q.size()) {
    
    
		int x = q.top().v; //取出队头
		int di = q.top().dis;
		q.pop();
		if (vis[x][di]) continue; //如果点x访问过,跳过,访问下一个队头
		vis[x][di] = 1; //访问x做标记
		for (int i = head[x]; i; i = edge[i].next) {
    
    
			int v = edge[i].v, w = edge[i].w;
			ll cos = edge[i].c;
			if (w + di > maxdis) continue;
			if (d[v][w + di] > d[x][di] + cos) {
    
     //松弛操作,更新距离
				d[v][w + di] = d[x][di] + cos;
				//cout << d[v][w + di] << endl;
				q.push(nod(d[v][w + di], v, w + di)); //把更新的距离和点入队,这里距离取负变成小根堆
			}
		}
	}
}
int dis(int i, int j) {
    
    
	return ceil(sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])));
}
int main() {
    
    
	scanf("%d%d%d%d%d%d", &sx, &sy, &tx, &ty, &maxdis, &c[0]);
	scanf("%d", &numc);
	for (int i = 1; i <= numc; i++) scanf("%d", &c[i]);
	scanf("%d", &n);
	x[0] = sx, y[0] = sy;
	x[n + 1] = tx, y[n + 1] = ty;
	for (int i = 1; i <= n; i++) {
    
    
		scanf("%d%d", &x[i], &y[i]);
		scanf("%d", &num[i]);
		for (int j = 1; j <= num[i]; j++) {
    
    
			scanf("%d%d", &v[i][j], &mod[i][j]);
			v[i][j]++;
		}
	}
	for (int i = 1; i <= n; i++) {
    
    
		add(0, i, dis(0, i), 1ll * dis(0, i) * c[0]);
		add(i, n + 1, dis(i, n + 1), 1ll * dis(i, n + 1) * c[0]);
	}
	add(0, n + 1, dis(0, n + 1), 1ll * dis(0, n + 1) * c[0]);
	for (int i = 1; i <= n; i++) {
    
    
		for (int j = 1; j <= num[i]; j++) {
    
    
			add(i, v[i][j], dis(i, v[i][j]), 1ll * dis(i, v[i][j]) * c[mod[i][j]]);
			add(v[i][j], i, dis(i, v[i][j]), 1ll * dis(i, v[i][j]) * c[mod[i][j]]);
		}
	}
	s = 0;
	dijkstra();
	ll ans = inf;
	for (int i = 0; i <= maxdis; i++) {
    
    
		ans = min(ans, d[n + 1][i]);
	}
	printf("%lld\n", ans == inf ? -1 : ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43680965/article/details/108673074
今日推荐