题意分析
一看到牛就知道是USACO(大雾
是一道最短路的升级应用,根据题意, 我们需要找到一个距离所有牛最短的牧场。那么只需要枚举所有牧场为起点,求此时所有其他牧场到它的最短路之和即可。然后输出所有牧场中最短距离即为答案。
样例
输入样例
3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5
输出样例
8
堆优化版的dijkstra
数据范围比较小,其实怎么求都可以。
C++ 代码
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 1000, M = 3000, INF = 0x3f3f3f3f;
int h[N], e[M], ne[M], w[M], idx;
int dist[N], cow[N], n, m, p;
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
int dijkstra_heap(int s)
{
memset(st, 0, sizeof st);
memset(dist, 0x3f, sizeof dist);
dist[s] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, s});
while(heap.size())
{
PII t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver]; i != -1; i = ne[i])
{
int j = e[i];
if(dist[j] > distance + w[i])
{
dist[j] = distance + w[i];
heap.push({dist[j], j});
}
}
}
int ans = 0;
for(int i = 1; i <= n; i ++)
{
int j = cow[i];
if(dist[j] == INF) return INF;
ans += dist[j];
}
return ans;
}
int main()
{
memset(h, -1, sizeof h);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> p >> m;
for(int i = 1; i <= n; i ++) cin >> cow[i];
while(m --)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
int ans = INF;
for(int i = 1; i <= p; i ++) ans = min(ans, dijkstra_heap(i));
cout << ans;
return 0;
}
我实在不理解为什么我的代码tie了
为啥这样写会wa
其他地方没问题,这里改成模板就A了
st[ver]在这之前已经被true了,所以一定不会进入堆里
把st[ver]改成st[j]就行了,当时想的是这里可以优化
这里加不加都一样。因为第一次出队时最短距离就确定了(后边不会再松弛这个点),同时标记上了数组st。
对的,加了可以优化一点
SPFA死的安详。。。。。。我也觉得应该按照牧场枚举,而不是奶牛
话说按照奶牛枚举是个什么思路?
看一下y总视频啊,貌似就是按照奶牛枚举的吧,记不太清了
实际上也就是一个个人习惯的问题吧。
理论上来讲y总的那个spafa理解起来比这个代码要难理解一些,
但实际上来讲这个时间复杂度差了那么亿点点(y总204ms,这个2084ms)。。。
其实都是可以解决的。就看喜欢写那种。。。
而且y总那个也不能算是按奶牛枚举的吧?好像只是换了一种最短路方法而已。。。。。
为什么这里N 要开到1000呀,开510 会 SE 。。。 还要这里边数请问要怎么算呀
510是牛的数量 牧场的数量才是点的数量 所以至少要开810~
必须使用优先队列吗
djkstra的堆优化版就是用优先队列(手写堆也可以)。其他的方法是不需要的。
这个题是数据加强了吗,怎么按照y总的代码提交上去不对呢
是吧
很好啊