此题考察了对于图的整体性质的观察和与拓扑序结合的最短路算法。
题目: 道路与航线
做法:
1、观察题目给出的图,如果去除单向边权可负的航线,图变成一块块连通块,连通块中的边都是非负且双向。
2、用拓扑排序的思想处理每个连通块,每个连通块内部用 D i j s k t r a Dijsktra Dijsktra 堆优化算法处理,如果有连到别的连通块的边,则那个连通块入度减去 1 (入度统计做为拓扑排序的入队指标)。
本题的收获:
1、精心观察图。
2、拓扑图的性质,连通块的处理。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
using namespace std;
const int M=150010,N=25010;
int n,dl,hx,s;
int idx,e[M],ver[M],head[N],ne[M];
int cnum,c[N],ind[N];
vector<int> bl[N];
int dist[N];
bool st[N];
queue<int> q;
void add(int a,int b,int c){
e[++idx]=c;
ver[idx]=b;
ne[idx]=head[a];
head[a]=idx;
}
void dfs(int s,int num){
c[s]=num;
bl[num].push_back(s);
for(int i=head[s];i;i=ne[i])
if(!c[ver[i]])
dfs(ver[i],num);
}
void dij(int t){
priority_queue<pii, vector<pii>,greater<pii> > heap;
for(int i=0;i<bl[t].size();i++){
heap.push({dist[bl[t][i]],bl[t][i]});
//cout<<dist[bl[t][i]]<<" "<<bl[t][i]<<endl;
}
while(heap.size()){
pii h=heap.top();
heap.pop();
int from=h.y;
if(st[from]) continue;
st[from] =true;
for(int i=head[from];i;i=ne[i]){
int val=e[i];
int to=ver[i];
if(c[from]!=c[to] && --ind[c[to]]==0) q.push(c[to]);
if(dist[to]>dist[from]+val){
dist[to]=dist[from]+val;
if(c[to]==c[from]) heap.push({dist[to],to}); //
}
}
}
}
void topsort(){
memset(dist,0x3f,sizeof(dist));
dist[s]=0;
for(int i=1;i<=cnum;i++)
if(c[s]==i || ind[i]==0)
q.push(i);
while(q.size()){
int t=q.front();
q.pop();
dij(t);
}
}
int main(){
memset(st,false,sizeof(st));
cin>>n>>dl>>hx>>s;
for(int i=1;i<=dl;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
for(int i=1;i<=n;i++)
if(!c[i]){
cnum++;
dfs(i,cnum);
}
for(int i=1;i<=hx;i++){
int a,b,z;
scanf("%d%d%d",&a,&b,&z);
add(a,b,z);
ind[c[b]]++;
}
topsort();
for(int i=1;i<=n;i++)
if(dist[i]>0x3f3f3f3f/2) cout<<"NO PATH"<<endl;
else cout<<dist[i]<<endl;
return 0;
}