ARC061E Snuke's Subway Trip

传送门

题目大意

已知某城市的地铁网由一些地铁线路构成,每一条地铁线路由某一个公司运营,该城市规定:若乘坐同一公司的地铁,从开始到换乘只需要一块钱,换乘其他公司的价格也是一块钱,问从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[2000100]; int id[2000100],fa[2000100],n,m,newn,d[2000100],used[2000100]; vector<int>v[2000100]; 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]=0; id[e[i].x]=id[e[i].y]=-1; } 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]==-1)id[xx]=++newn; v[e[i].x].push_back(id[xx]); v[id[xx]].push_back(e[i].x); used[e[i].x]=1; } if(!used[e[i].y]){ if(id[yy]==-1)id[yy]=++newn; v[e[i].y].push_back(id[yy]); v[id[yy]].push_back(e[i].y); used[e[i].y]=1; } } } queue<int>q; int main(){ int i,l=1; scanf("%d%d",&n,&m); newn=n; for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].c); sort(e+1,e+m+1,cmp); for(i=2;i<=m;i++) if(e[i].c!=e[i-1].c){ deal(l,i-1); l=i; } deal(l,m); memset(d,-1,sizeof(d)); d[1]=0; q.push(1); while(!q.empty()){ int x=q.front(); q.pop(); for(i=0;i<(int)v[x].size();i++) if(d[v[x][i]]==-1){ d[v[x][i]]=d[x]+1; q.push(v[x][i]); } } if(d[n]==-1)puts("-1"); else cout<<d[n]/2<<endl; return 0; }
//做法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;
}

转载于:https://www.cnblogs.com/yzxverygood/p/9312178.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值