思路
每个点有三种状态,分别是经过0、1、2次限高杆
每个点对应的最短路有三种,分别是d[i][0]、d[i][1]、d[i][2]
每个点对应的状态是否在队列中用st[i][0]、st[i][1]、st[i][2]
标记
则从A到B最多经过2个限高杆的最短路径长度为:min(f[n][0], f[n][1], f[n][2])
C++ 代码
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
typedef pair<int, int> PII;
struct Node //每个点指向的下一个节点
{
int node;
int w;
int no; //是否有限高杆
};
const int N = 10010;
int n, m;
vector<Node> g[N];
int d[N][3];
bool st[N][3];
void spfa()
{
memset(d, 0x3f, sizeof d);
d[1][0] = d[1][1] = d[1][2] = 0;
queue<PII> q;
q.push({1, 0});
while (q.size())
{
auto tt = q.front();
q.pop();
int t = tt.first; //当前节点
int cnt = tt.second; //当前经过的限高杆数量
st[t][cnt] = false;
int num = g[t].size();
for (int i = 0; i < num; i ++ )
{
int j = g[t][i].node;
int w = g[t][i].w;
int no = g[t][i].no;
if (cnt + no < 3 && d[j][cnt + no] > d[t][cnt] + w) //不能超过三个限高杆
{
d[j][cnt + no] = d[t][cnt] + w;
if (!st[j][cnt + no])
{
q.push({j, cnt + no});
st[j][cnt + no] = true;
}
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i ++ )
{
int a, b, c, f;
scanf("%d%d%d%d", &a, &b, &c, &f);
g[a].push_back({b, c, f});
g[b].push_back({a, c, f});
}
spfa();
cout << d[n][0] - min(min(d[n][0], d[n][1]), d[n][2]);
return 0;
}
开始时只加入一种状态吧。
已修改,感谢指正!
d[i][j]
:表示 点i
且限高杆不超过j
的距离