【一句话题意】C 国的道路网络由m条双向线路组成,有n个城市在道路网络上。每条线路途经一些城市(可能会经过多次同一城市),最多有li个城市,位于线路上的两个城市a,b 通过i 号线路互相抵达的费用为w[i][a] + w[i][b]。现在有T个询问,询问两城市互相到达的最小费用。
n<=1e5;m<=300;li,T,w[i][j]<=2000。
【分析】此题暴力spfa可以骗到50分,对于第一遍的暴力是一个不错的选择。
回归到正解,我们可以看成每次进出站记一次站点的费用。因为m值较小,我们可以对每两条线路之间的转站进行floyd。每次询问时,枚举从a、b两点出发各个线路的转站,费用再加上两个站点的出入站费,求最小值。
【code】
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxm=310;
const int maxl=2010;
const int maxn=1e5+1000;
int n,m;
struct E{
int id,c,nxt;
}road[maxm*maxl];
int head[maxn],tot;
int f[maxm][maxm];
inline void read(int &x){
x=0;char tmp=getchar();
while(tmp<'0'||tmp>'9') tmp=getchar();
while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
inline void add_road(int x,int id,int c){
road[tot].id=id;
road[tot].c=c;
road[tot].nxt=head[x];
head[x]=tot++;
}
int main(){
memset(head,-1,sizeof(head));
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,w,cnt;read(cnt);
for(int j=1;j<=cnt;j++)
read(x),read(w),add_road(x,i,w);
}
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
f[i][j]=1<<29;
for(int i=1;i<=m;i++)
f[i][i]=0;
for(int i=1;i<=n;i++){//node
for(int j=head[i];j!=-1;j=road[j].nxt){//line1
for(int k=head[i];k!=-1;k=road[k].nxt){//line2
if(j==k) continue;
int x=road[j].id,y=road[k].id,w=road[j].c+road[k].c;
f[y][x]=f[x][y]=min(f[x][y],w);
}
}
}
for(int k=1;k<=m;k++)
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
int a,b;read(a),read(b);
while(a||b){
int ans=-1;
for(int i=head[a];i!=-1;i=road[i].nxt){
int u=road[i].id;
for(int j=head[b];j!=-1;j=road[j].nxt){
int v=road[j].id;
if(f[u][v]==1<<29) continue;
if(road[i].c+road[j].c+f[u][v]<ans||ans==-1) ans=road[i].c+road[j].c+f[u][v];
}
}
printf("%d\n",ans);
read(a),read(b);
}
return 0;
}