USACO18DEC-Fine_Dining


题面

思路:

我们先考虑暴力,我们可以先按题意模拟先从N点跑一次最短路,然后我们在从每个草垛跑一次最短路,时间复杂度$O(kn)$,得到$70$分的好成绩。我们再考虑优化,我们发现我们从每个草垛跑最短路时跑了许多冗余状态。我们可以考虑在图上动手脚,我们将图进行分层,我们先在原图上跑一遍SPFA,然后再将图复制一份,从第一个图的干草跺向第二图的相同节点连一条-w的有向边。最后比较两次的dis值即可

代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int maxm = 1e5 + 10;
const int maxn = 1e5 + 10;
int dis[maxn],dist[maxn],n,m,k,head[maxn],tot;
bool vis[maxn];
struct edge
{
int next,to,w;
}e[maxm << 2];
void add(int u,int v,int w)
{
e[++tot] = (edge){head[u],v,w};
head[u] = tot;
}
void spfa(int st)
{
memset(dis,0x3f,sizeof(dis));
queue<int>q;
q.push(st);vis[st] = 1;dis[st] = 0;
while(q.size())
{
int x = q.front();q.pop();vis[x] = 0;
for(int i = head[x] ; i ; i = e[i].next)
{
int v = e[i].to;
if(dis[v] > dis[x] + e[i].w){
dis[v] = dis[x] + e[i].w;
if(!vis[v]){
vis[v] = 1;
q.push(v);
}
}
}
}
}
void spfa2(int st)
{
memset(dist,0x3f,sizeof(dist));
queue<int>q;
vis[st] = 1;
q.push(st);
dist[st] = 0;
while(q.size())
{
int x = q.front();q.pop();
for(int i = head[x] ; i ; i = e[i].next)
{
int v = e[i].to;
if(dist[v] > dist[x] + e[i].w){
dist[v] = dist[x] + e[i].w;
if(!vis[v]){
dist[v] = dist[x] + e[i].w;
q.push(v);
}
}
}
}
}
signed main()
{
cin >> n >> m >> k;
for(int i = 1,u,v,w ; i <= m ; ++ i)
{
cin >> u >> v >> w;
add(u,v,w);add(v,u,w);
add(u + n,v + n,w);add(v + n,u + n,w);
}
spfa(n);
for(int i = 1,x,y ; i <= k ; ++ i)
{
cin >> x >> y;
add(x,x + n,-y);
}
spfa2(n);
for(int i = 1 ; i < n ; ++ i)
{
if(dis[i] >= dist[i + n])cout << 1 << endl;
else cout << 0 << endl;
}
return 0;
}