- 难点是如何将楼层转化到图中,
-
用2个点将一个面(楼层)抽象出来,1个
入点,1个出点
-
一个面上的所有点都指向
出点
,权值为0 -
入点
指向该面所有的点(除了出点),权值为0 -
入点指向出点
,权值为
0
, -
中间的楼层的出点分别指向
上一层的入点
和
下一层的入点
,权值为
c
.将所有楼层都连接起来 -
没有最短路则
dist[n] = MAX
- dij
#include <iostream>
#include <string.h>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 3e5+5;
const int MAX = 0x3f3f3f3f;
vector<pair<int,int> > e[maxn];
int n,m,cost;
int dist[maxn];
int dij() {
priority_queue<pair<int,int> > que;
memset(dist,0x3f,sizeof dist);
que.push( make_pair(0,1) );
dist[1] = 0;
while (!que.empty()) {
int cur = que.top().second; que.pop();
for (int i=0; i<e[cur].size(); i++) {
int to = e[cur][i].first;
int div = e[cur][i].second;
if (dist[to] > dist[cur] + div) {
dist[to] = dist[cur] + div;
que.push( make_pair(-dist[to],to) );
}
}
}
return dist[n];
}
int main() {
// freopen("a.txt","r",stdin);
int times,k=0;
scanf("%d",×);
while (times--) {
scanf("%d%d%d",&n,&m,&cost);
// 楼层抽象化成2个点,一个入点,一个出点
int temp;
for (int i=1; i<=n; i++) { //i代表点,temp是该点的楼层
scanf("%d",&temp);
e[temp*2+n-1].push_back( make_pair(i,0) ); // 入点指向平面的点
e[i].push_back( make_pair(temp*2+n,0) ); // 平面中的点指向出点
}
// 每个点之间的边
int from,to,div;
for (int i=1; i<=m; i++) {
scanf("%d%d%d",&from,&to,&div);
e[from].push_back( make_pair(to,div) );
e[to].push_back( make_pair(from,div));
}
// 当前层的 出点 与 相邻层的 入点 建边
for (int i=1; i<=n; i++) {
from = 2 * i + n; // 出点
if (i > 1) {
to = from - 3;
// 该层的出点,到上一层的入点
e[from].push_back( make_pair(to,cost) );
}
if (i < n) {
to = from + 1;
// 该层的出点,到下一层的入点
e[from].push_back( make_pair(to,cost) );
}
}
int ans = dij();
if (ans == MAX) printf("Case #%d: -1\n",++k);
else printf("Case #%d: %d\n",++k,ans);
// 清除上一组数据
for (int i=1; i<=3 * n; i++) e[i].clear();
}
return 0;
}
- spfa
#include <iostream>
#include <string.h>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 3e5+5;
const int MAX = 0x3f3f3f3f;
vector<pair<int,int> > e[maxn];
int n,m,cost;
int dist[maxn];
bool vis[maxn];
int spfa() {
queue<int> que;
memset(vis,0,sizeof vis);
memset(dist,0x3f,sizeof dist);
que.push(1);
dist[1] = 0; vis[1] = 1;
while (!que.empty()) {
int cur = que.front(); que.pop();
vis[cur] = 0;
for (int i=0; i<e[cur].size(); i++) {
int to = e[cur][i].first;
int div = e[cur][i].second;
if (dist[to] > dist[cur] + div) {
dist[to] = dist[cur] + div;
if (!vis[to]) {
vis[to] = 1;
que.push(to);
}
}
}
}
return dist[n];
}
int main() {
// freopen("a.txt","r",stdin);
int times,k=0;
scanf("%d",×);
while (times--) {
scanf("%d%d%d",&n,&m,&cost);
// 楼层抽象化成2个点,一个入点,一个出点
int temp;
for (int i=1; i<=n; i++) { //i代表点,temp是该点的楼层
scanf("%d",&temp);
e[temp*2+n-1].push_back( make_pair(i,0) ); // 入点指向平面的点
e[i].push_back( make_pair(temp*2+n,0) ); // 平面中的点指向出点
}
// 每个点之间的边
int from,to,div;
for (int i=1; i<=m; i++) {
scanf("%d%d%d",&from,&to,&div);
e[from].push_back( make_pair(to,div) );
e[to].push_back( make_pair(from,div));
}
// 当前层的 出点 与 相邻层的 入点 建边
for (int i=1; i<=n; i++) {
from = 2 * i + n; // 出点
if (i > 1) {
to = from - 3;
// 该层的出点,到上一层的入点
e[from].push_back( make_pair(to,cost) );
}
if (i < n) {
to = from + 1;
// 该层的出点,到下一层的入点
e[from].push_back( make_pair(to,cost) );
}
}
int ans = spfa();
if (ans == MAX) printf("Case #%d: -1\n",++k);
else printf("Case #%d: %d\n",++k,ans);
// 清除上一组数据
for (int i=1; i<=3 * n; i++) e[i].clear();
}
return 0;
}
版权声明:本文为qq_43580151原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。