题目大意
已知某城市的地铁网由一些地铁线路构成,每一条地铁线路由某一个公司运营,该城市规定:若乘坐同一公司的地铁,从开始到换乘只需要一块钱,换乘其他公司的价格也是一块钱,问从1号地铁站到n号地铁站的最低价格。
分析
做法1:
这个题在原图上跑显然是不可能的,所以我们需要考虑如何重新构图,首先我们想到如果数个点能被一条线连接就可以不花钱,所以我们可以考虑把他们缩成一点,我们有不难想到如果有两条线路是一家公司的但是它们不相连则它们和由不同两个公司运营效果是一样的。于是我们便得到了构图思路:枚举每一家公司,将一家公司中所有能相连的点连到一个新点上,对于每家公司可能会产生多个新点,这就是我们之前说的不相连的由同一公司运营的点相当于由两个不同公司运行的,我们有了新点后将原来点与它现在所属的“新公司”相连,这样就构成了一个二分图,将每条边的权值赋为1,bfs求最短路最终答案除以2就行了。
做法2:
我们不再考虑缩点而考虑拆点,将每一个站点按连接它的铁路的所属公司拆违k个不同点,然后再额外创建一个0点,每一次换公司都要先走到这个0点再转换到其它公司。注意代码中的p.p表示当前车站,p.b表示所属公司。p.c为到达此站的最小花费,具体实现见代码。
代码
//做法1
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define sp cout<<"---------------------------------------------------"<<endl;
struct node {
int x,y,c;
}e[];
int id[],fa[],n,m,newn,d[],used[];
vector<int>v[];
inline bool cmp(const node a,const node b){
return a.c<b.c;
}
inline int sf(int x){return fa[x]==x?x:fa[x]=sf(fa[x]);}
inline void deal(int le,int ri){
int i;
for(i=le;i<=ri;i++){
fa[e[i].x]=e[i].x;
fa[e[i].y]=e[i].y;
used[e[i].x]=used[e[i].y]=;
id[e[i].x]=id[e[i].y]=-;
}
for(i=le;i<=ri;i++)
if(sf(e[i].x)!=sf(e[i].y)){
fa[sf(e[i].x)]=sf(e[i].y);
}
for(i=le;i<=ri;i++){
int xx=sf(e[i].x),yy=sf(e[i].y);
if(!used[e[i].x]){
if(id[xx]==-)id[xx]=++newn;
v[e[i].x].push_back(id[xx]);
v[id[xx]].push_back(e[i].x);
used[e[i].x]=;
}
if(!used[e[i].y]){
if(id[yy]==-)id[yy]=++newn;
v[e[i].y].push_back(id[yy]);
v[id[yy]].push_back(e[i].y);
used[e[i].y]=;
}
}
}
queue<int>q;
int main(){
int i,l=;
scanf("%d%d",&n,&m);
newn=n;
for(i=;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].c);
sort(e+,e+m+,cmp);
for(i=;i<=m;i++)
if(e[i].c!=e[i-].c){
deal(l,i-);
l=i;
}
deal(l,m);
memset(d,-,sizeof(d));
d[]=;
q.push();
while(!q.empty()){
int x=q.front();
q.pop();
for(i=;i<(int)v[x].size();i++)
if(d[v[x][i]]==-){
d[v[x][i]]=d[x]+;
q.push(v[x][i]);
}
}
if(d[n]==-)puts("-1");
else cout<<d[n]/<<endl;
return ;
}
//做法2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define sp cout<<"---------------------------------------------------"<<endl;
#define foreach(i,dat) for(__typeof(dat.begin()) i = dat.begin();i!=dat.end();++i)
const int inf=1e9+7;
struct node {
int p,b,c;
};
inline bool operator < (node x,node y){return x.c>y.c;}
map<int,vector<int> >e[100100];
vector<int>v[100100];
map<int,int>d[100100];
priority_queue<node>q;
int main(){
int n,m,i,x,y,z;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
x--,y--;
e[x][z].push_back(y);
e[y][z].push_back(x);
v[x].push_back(z);
v[y].push_back(z);
}
q.push({0,0,0});;
d[0][0]=0;
while(!q.empty()){
node p=q.top();
q.pop();
if(d[p.p][p.b]!=p.c)continue;
if(d[p.p].find(0)==d[p.p].end()||d[p.p][0]>p.c){
d[p.p][0]=p.c;
q.push({p.p,0,p.c});
}
if(!p.b){
for(i=0;i<(int)v[p.p].size();i++)
if(d[p.p].find(v[p.p][i])==d[p.p].end()||d[p.p][v[p.p][i]]>p.c+1){
d[p.p][v[p.p][i]]=p.c+1;
q.push({p.p,v[p.p][i],p.c+1});
}
continue;
}
for(i=0;i<(int)e[p.p][p.b].size();i++)
if(d[e[p.p][p.b][i]].find(p.b)==d[e[p.p][p.b][i]].end()
||d[e[p.p][p.b][i]][p.b]>p.c){
d[e[p.p][p.b][i]][p.b]=p.c;
q.push({e[p.p][p.b][i],p.b,p.c});
}
}
int ans=inf;
for(map<int,int>::iterator it=d[n-1].begin();it!=d[n-1].end();it++)
ans=min(ans,it->second);
if(ans==inf)puts("-1");
else printf("%d\n",ans);
return 0;
}