【题目链接】
ybt 1497:农场派对
洛谷 P1821 [USACO07FEB] Cow Party S
【题目考点】
1. 图论:最短路径
- 朴素Dijkstra
- Dijkstra堆优化
- SPFA
【解题思路】
每个农场是一个顶点,农场之间的道路是边,该图是有向图。
第
x
x
x号农场举办派对,对于任意的来自第
s
s
s号农场的牛,需要先走一条从顶点
s
s
s出发到顶点
x
x
x的最短路径到达开派对的农场,再走一条从顶点
x
x
x到顶点
s
s
s的路径回家。
使用dijkstra或spfa算法求以顶点
x
x
x为源点的单源最短路径问题,获取从顶点
x
x
x到任意顶点的最短路径。
要想求出从其它顶点到顶点
x
x
x的最短路径,直观的想法是求出任意顶点到任意顶点的路径,也就是求解多源最短路问题。而求多源最短路的floyd算法的时间复杂度是
O
(
n
3
)
O(n^3)
O(n3),本题
n
n
n最大为1000,
n
3
=
1
0
9
>
1
0
8
n^3=10^9>10^8
n3=109>108,无法在1s内完成运行。
此处应该考虑使用反图。
原图中顶点A到顶点B的路径,就是一条反图中顶点B到顶点A的路径。
原图中顶点A到顶点B的所有路径中最短的路径,就是反图中顶点B到顶点A的所有路径中最短的路径。
因此,要想求原图中顶点
y
y
y到顶点
x
x
x的最短路径,可以建立反图,求反图中顶点
x
x
x到顶点
y
y
y的最短路径。
在反图中求解从顶点
x
x
x出发的单源最短路径问题,就可以获得原图中任意其它顶点到顶点
x
x
x的最短路径。
枚举每个顶点,对于顶点
i
i
i,求顶点
x
x
x到顶点
i
i
i的最短路径和顶点
i
i
i到顶点
x
x
x的最短路径加和的最大值,即为本题结果。
【题解代码】
解法1:Dijkstra堆优化算法
#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct Path
{
int u, d;
bool operator < (const Path &b) const
{
return b.d < d;
}
};
struct Edge
{
int v, w;
};
int n, m, x, dis_g[N], dis_rg[N], ans;//dis_g[i]:从x到i的最短路径 dis_rg[i]:从i到x的最短路径
bool vis[N];
vector<Edge> g[N], rg[N];//邻接表 g:原图 rg:反图
void dijkstra(vector<Edge> *edge, int *dis)
{
priority_queue<Path> pq;
memset(dis, 0x3f, 4*N);//注意此处第三个参数不能使用sizeof(dis),因为现在dis是指针,没有数组长度。
memset(vis, 0, sizeof(vis));
dis[x] = 0;
pq.push(Path{x, 0});
while(!pq.empty())
{
int u = pq.top().u;
pq.pop();
if(vis[u])
continue;
vis[u] = true;
for(Edge e : edge[u])
{
int v = e.v, w = e.w;
if(!vis[v] && dis[v] > dis[u]+w)
{
dis[v] = dis[u]+w;
pq.push(Path{v, dis[v]});
}
}
}
}
int main()
{
int u, v, w;
cin >> n >> m >> x;
for(int i = 1; i <= m; ++i)
{
cin >> u >> v >> w;
g[u].push_back(Edge{v, w});
rg[v].push_back(Edge{u, w});
}
dijkstra(g, dis_g);
dijkstra(rg, dis_rg);
for(int i = 1; i <= n; ++i)
ans = max(ans, dis_g[i]+dis_rg[i]);
cout << ans;
return 0;
}
解法2:朴素Dijkstra算法
#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct Edge
{
int v, w;
};
int n, m, x, dis_g[N], dis_rg[N], ans;//dis_g[i]:从x到i的最短路径 dis_rg[i]:从i到x的最短路径
bool vis[N];
vector<Edge> g[N], rg[N];//邻接表 g:原图 rg:反图
void dijkstra(vector<Edge> *edge, int *dis)
{
memset(dis, 0x3f, 4*N);//注意此处第三个参数不能使用sizeof(dis),因为现在dis是指针,没有数组长度。
memset(vis, 0, sizeof(vis));
dis[x] = 0;
for(int k = 1; k <= n; ++k)
{
int u = 0;
for(int i = 1; i <= n; ++i) if(!vis[i] && (u == 0 || dis[i] < dis[u]))
u = i;
vis[u] = true;
for(Edge e : edge[u])
{
int v = e.v, w = e.w;
if(!vis[v] && dis[v] > dis[u]+w)
dis[v] = dis[u]+w;
}
}
}
int main()
{
int u, v, w;
cin >> n >> m >> x;
for(int i = 1; i <= m; ++i)
{
cin >> u >> v >> w;
g[u].push_back(Edge{v, w});
rg[v].push_back(Edge{u, w});
}
dijkstra(g, dis_g);
dijkstra(rg, dis_rg);
for(int i = 1; i <= n; ++i)
ans = max(ans, dis_g[i]+dis_rg[i]);
cout << ans;
return 0;
}
解法3:SPFA算法
#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct Edge
{
int v, w;
};
int n, m, x, dis_g[N], dis_rg[N], ans;//dis_g[i]:从x到i的最短路径 dis_rg[i]:从i到x的最短路径
bool inQue[N];
vector<Edge> g[N], rg[N];//邻接表 g:原图 rg:反图
void spfa(vector<Edge> *edge, int *dis)
{
memset(dis, 0x3f, 4*N);//注意此处第三个参数不能使用sizeof(dis),因为现在dis是指针,没有数组长度。
memset(inQue, 0, sizeof(inQue));
queue<int> que;
dis[x] = 0;
que.push(x);
inQue[x] = true;
while(!que.empty())
{
int u = que.front();
que.pop();
inQue[u] = false;
for(Edge e : edge[u])
{
int v = e.v, w = e.w;
if(dis[v] > dis[u]+w)
{
dis[v] = dis[u]+w;
if(!inQue[v])
{
que.push(v);
inQue[v] = true;
}
}
}
}
}
int main()
{
int u, v, w;
cin >> n >> m >> x;
for(int i = 1; i <= m; ++i)
{
cin >> u >> v >> w;
g[u].push_back(Edge{v, w});
rg[v].push_back(Edge{u, w});
}
spfa(g, dis_g);
spfa(rg, dis_rg);
for(int i = 1; i <= n; ++i)
ans = max(ans, dis_g[i]+dis_rg[i]);
cout << ans;
return 0;
}

423

被折叠的 条评论
为什么被折叠?



