题解 P2984 【[USACO10FEB]Chocolate Giving S】
_NaCly_Fish · · 题解
关于Floyd,它太慢了
关于spfa,它死了
关于dijkstra,还是用它吧
步入正题:
这道题,千万不要被题面所误导
题目大意:点u到点1的最短路+点1到点v的最短路
但是,您要是照着这个思路写代码的话,只能拿到50分,T了5个点
显然,这个做法不够优秀
进一步,我们发现,在第i头奶牛的行动中,肯定会经过1号点
所以,只要跑一边dijkstra就好了,把起点设为1
每当进行一次询问,就输出d[u]+d[v] (d[]记录最短距离)
//注释都在代码里了
上代码:(vector存图+dijkstra+堆优化)
//代码重在实用,不在华丽的操作
#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
int n,m,t,d[50010],ans;
//n个节点,m条边,t次询问,d[]存最短距离,ans为每次询问的答案
struct edge
{
int to,cost;
};
vector<edge>G[50010];//vector存图
typedef pair<int,int>P;//定义一个pair类型的P(只是为了写起来简单一点)
void dijkstra(int s)//s为起点,在这道题里就是1
{
priority_queue<P,vector<P>,greater<P> >q;
//一个P类型(pair)类型的优先队列
for(int i=1;i<=n;i++) d[i]=1e9;//赋初值1e9
d[s]=0;//自己到自己的距离是0
q.push(P{0,s});//加入队列等待处理
while(!q.empty())
{
P p=q.top();//取队首
q.pop();
//声明一下:p.first代表的是一个距离,而p.second代表的是一个点,
//Tell一个不为人知的秘密,
//若把p.first设为一个点,而把p.second设为一个距离,
//程序的速度就没有第一个优秀(亲测)
int v=p.second;//也是为了写起来简便一点,
if(d[v]<p.first) continue;//如果已经是一个最短距离了,continue;
for(int i=0;i<G[v].size();i++)//循环点v连接的所有点
{
edge e=G[v][i];
if(d[e.to]>d[v]+e.cost)//松弛操作,贪心思想
{
d[e.to]=d[v]+e.cost;//更新d[e.to]的值
q.push(P{d[e.to],e.to});//重新加入到队列等待处理
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&t);
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(edge{v,w});//注意,这个图是一个无向图
G[v].push_back(edge{u,w});
}
dijkstra(1);
//以1号点为起点进行dijkstra(),便可获得1号点到其它任意一点的最短距离
while(t--)
{
ans=0;
int u,v;
scanf("%d%d",&u,&v);
ans=d[u]+d[v];//直接输出答案
printf("%d\n",ans);
}
return 0;//养成良好习惯
}
这世界上不缺少什么水题,而是缺少发现水题的眼睛
看我写的这么认真,是否可以点个赞再走呢?