USACO的快乐农场题目

题目大意
求结点1到n的严格次次短路径。

因为不久前刚刚看过了最短路计数这道题目,所以就想在求最短路的时候,用dis数组记录最短路和次短路,然后就愉快的打完了代码,过了样例,然后50……

下面是50分代码

#include <bits/stdc++.h>
#define id tmp.second
#define di tmp.first
using namespace std;
typedef pair<int, int> PI;
const int M = 300500;
int n, r, head[M], tot, dis[M][2], vis[M];
struct EDGE{
int v, w, nxt;
}e[M];
priority_queue<PI, vector<PI>, greater<PI> > q;
PI tmp;

void add(int x, int y, int z)
{
e[++tot].v = y, e[tot].nxt = head[x], e[tot].w = z, head[x] = tot;
}

void Dijkstra()
{
memset(dis, 0x4f, sizeof(dis));
dis[1][0] = dis[1][1] = 0;
q.push(make_pair(0, 1));
while (!q.empty())
{
tmp = q.top(), q.pop();
if (vis[id]) continue;
vis[id] = 1;
for (int i = head[id]; i; i = e[i].nxt)
{
if (dis[e[i].v][0] > di + e[i].w)
{
dis[e[i].v][1] = dis[e[i].v][0], dis[e[i].v][0] = di + e[i].w;
if (!vis[e[i].v]) q.push(make_pair(dis[e[i].v][0], e[i].v));
}
else if (dis[e[i].v][1] > di + e[i].w) dis[e[i].v][1] = di + e[i].w;
}
}
}

int main()
{
int x, y, z;
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> r;
for (int i = 1; i <= r; ++i) cin >> x >> y >> z, add(x, y, z), add(y, x, z);
Dijkstra();
printf("%d", dis[n][1]);
return 0;
}

然后,我重新想了想我在求最短路的时候的判断,发现50这个样子写,最小值可能会覆盖次小值,因为我只判断了一遍的范围,没有限制次小值严格小于最小值。而且题目要求一条路可以重复走多次,所以我增加了每个点可以经过的次数。
判断部分就成了这个样子

for (int i = head[id]; i; i = e[i].nxt)
{
if (dis[e[i].v][0] > di + e[i].w)
{
dis[e[i].v][1] = dis[e[i].v][0], dis[e[i].v][0] = di + e[i].w;
if (dis[e[i].v][1] > dis[id][1] + e[i].w && dis[e[i].v][0] < dis[id][1] + e[i].w)
dis[e[i].v][1] = dis[id][1] + e[i].w;
if (vis[e[i].v] < 2) q.push(make_pair(dis[e[i].v][0], e[i].v));
}
else
if (dis[e[i].v][1] > di + e[i].w && dis[e[i].v][0] < di + e[i].w)
{
dis[e[i].v][1] = di + e[i].w;
q.push(make_pair(dis[e[i].v][0], e[i].v));
}
else
if (dis[e[i].v][1] > dis[id][1] + e[i].w && dis[e[i].v][0] < dis[id][1] + e[i].w)
dis[e[i].v][1] = dis[id][1] + e[i].w;
}

这样就过了90分!
然后下载了错误数据,发现还是错在了一条边可以走多次的问题上。因为走多次的话,第一个点的次短路就不一定是0了,所以我把初始化只改成了初始化1号点的最短路。这样就过了这个题。
下面是AC代码

#include <bits/stdc++.h>
#define id tmp.second
#define di tmp.first
using namespace std;
typedef pair<int, int> PI;
const int M = 300500;
int n, r, head[M], tot, dis[M][2], vis[M];
struct EDGE{
int v, w, nxt;
}e[M];
priority_queue<PI, vector<PI>, greater<PI> > q;
PI tmp;

void add(int x, int y, int z)
{
e[++tot].v = y, e[tot].nxt = head[x], e[tot].w = z, head[x] = tot;
}

void Dijkstra()
{
memset(dis, 0x4f, sizeof(dis));
dis[1][0] = 0;
q.push(make_pair(0, 1));
while (!q.empty())
{
tmp = q.top(), q.pop();
if (vis[id] == 2) continue;
++vis[id];
for (int i = head[id]; i; i = e[i].nxt)
{
if (dis[e[i].v][0] > di + e[i].w)
{
dis[e[i].v][1] = dis[e[i].v][0], dis[e[i].v][0] = di + e[i].w;
if (dis[e[i].v][1] > dis[id][1] + e[i].w && dis[e[i].v][0] < dis[id][1] + e[i].w)
dis[e[i].v][1] = dis[id][1] + e[i].w;
if (vis[e[i].v] < 2) q.push(make_pair(dis[e[i].v][0], e[i].v));
}
else
if (dis[e[i].v][1] > di + e[i].w && dis[e[i].v][0] < di + e[i].w)
{
dis[e[i].v][1] = di + e[i].w;
if (vis[e[i].v] < 2) q.push(make_pair(dis[e[i].v][0], e[i].v));
}
else
if (dis[e[i].v][1] > dis[id][1] + e[i].w && dis[e[i].v][0] < dis[id][1] + e[i].w)
dis[e[i].v][1] = dis[id][1] + e[i].w;
}
}
}

int main()
{
int x, y, z;
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> r;
for (int i = 1; i <= r; ++i) cin >> x >> y >> z, add(x, y, z), add(y, x, z);
Dijkstra();
printf("%d", dis[n][1]);
return 0;
}
01-19 02:02