原题链接:E-小苯的网络配置(A组、B组、C组)_2024年第七届传智杯程序设计挑战赛复赛(第一场)
解题思路:最短路问题用Dijksta算法,这题的难点在于传输记录,怎么确定当前路径就是最短路,并且记录每条分支是不是最短路。观察得到对于每条边 (u,v),如果此边在某条最短路上的话,则一定满足 dist(1,u)+dist(v,n)+w[u,v]=dist(1,n),即最短路从 1 到 u,再从 u 到 v,再从 v 到 n。或者将 u,v 反过来的这个条件也成立。因此我们先预处理从 1 出发的 dijkstra,再预处理一个 从n出发的 dijkstra,求出 n 到所有点的最短路记作 dn。接着只需要枚举每条边 (u,v),进行 check 即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
typedef pair<long long,int> PII;
long long e[N],ne[N],idx,h[N],w[N];
//dist[0]记录从1—n的最短路,dist[1]记录从n-1的最短路
long long dist[2][N];
long long edge[3][N];
int n,m;
//创建邻接表
void add(int a,int b,long long c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
//进行check
bool check(long long a,long long b,long long c){
return dist[0][a]+dist[1][b]+c==dist[0][n];
}
// Dijkstra算法
void Dijkstra(int s,long long dist[]){
bool st[N];
for(int i = 0; i <= n; i++)
dist[i] = 2e18, st[i] = 0;
dist[s]=0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,s});
while(heap.size()){
auto t=heap.top().second;
heap.pop();
if(st[t])continue;
st[t]=true;
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
heap.push({dist[j],j});
}
}
}
}
void solve(){
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
//保存节点
edge[0][i]=a;
edge[1][i]=b;
edge[2][i]=c;
}
//预处理最短路
Dijkstra(1,dist[0]);
Dijkstra(n,dist[1]);
//检查
for(int i=1;i<=m;i++){
long long a=edge[0][i],b=edge[1][i],c=edge[2][i];
if(check(a,b,c)||check(b,a,c))cout<<1;
else cout<<0;
}
cout<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
}