P9650 [SNCPC2019] Escape Plan
开始
敲代码前问问自己:如何证明你的算法的正确性?
启发
我们一开始在节点1,假如有abcd四条边,且我们已知 从每条边出发到达终点的最短距离 \(a<b<c<d\) 且 \(d[1]=3\)
请问我们要封 节点1 的哪条边?
答案显然是abc
那么好接下来我们走边d,假设到达了节点3,我们把节点3当成节点1,又回到了上述情景
一句话总结
我们要率先封住那些 使得当前节点到终点距离最小的边
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxs=2e18;
int e[100005];
int d[100005];
ll dis[100005];
struct node
{
int to,len;
};
vector<node> G[100005];
struct fresh
{
int pos,val;
bool operator<(const fresh &b) const
{
return b.val<val;
}
};
void solve()
{
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=k;i++) cin>>e[i];
for(int i=1;i<=n;i++)
{
cin>>d[i];
dis[i]=maxs;
}
for(int i=1;i<=m;i++)
{
int x,y,w;
cin>>x>>y>>w;
G[x].push_back({y,w});
G[y].push_back({x,w});
}
priority_queue<fresh> q;
for(int i=1;i<=k;i++)
{
q.push({e[i],0});
d[e[i]]=0;
}
while(q.size())
{
int now=q.top().pos,val=q.top().val;
q.pop();
if(dis[now]<=val) continue;
if(d[now])
{
d[now]--;
continue;
}
dis[now]=val;
for(auto next:G[now])
{
int to=next.to,len=next.len;
if(dis[now]+len<dis[to])
{
q.push({to,len+dis[now]});
}
}
}
if(dis[1]!=maxs) cout<<dis[1]<<"\n";
else cout<<"-1\n";
for(int i=1;i<=n;i++)
{
G[i].clear();
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}