【最短路-拆点】ARC061Cすぬけ君の地下鉄旅行/Snuke's Subway Trip
题目解析
刚开始想的是分层图,同个公司的边是同一层。走的时候你可以在同一层随便乱走,然后可以跑到另外一层的对应点去,这需要\(1\)的花费。
所以可以想到如下建边方式:每一层之间的边的边权为\(0\),同一个点的任意两层的点之间边权为\(1\),即表示换乘的花费为\(1\)。
发现这样建边边数会很多,比如一条边在\(i\)层都出现过 那么这个点就要建\(\frac {i(i-1)}{2}\)条边。
可以整一个虚点把每一层的点都连在一起,相当于搞一个换乘站点出来。
每个点换乘到另一个层的点需要经过\(2\)条边 所以每个点到换乘点的边权为\(0.5\)
避免浮点运算 所以最后除以\(2\)就可以了
后来还发现了一种更加简单暴力的方法:就是在做最短路的时候,判断一下,如果前驱边和这条边的公司一样,那么费用就是\(0\),否则为\(1\)(记录的东西变多了)不过这个我没有写qwq
►Code View
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<ctime>
#include<map>
using namespace std;
#define N 1000005
#define LL long long
#define INF 0x3f3f3f3f
#define inf 0x7fffffff
int rd()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
return f*x;
}
int n,m,s;
int c[N],tot;//对公司编号进行离散化
vector<pair<int,LL> >G[N];
LL d[N];
priority_queue< pair<LL,int>, vector< pair<LL,int> >,greater<pair<LL,int> > >Q;
map<pair<int,int>,int> mp;//编号为i的在第j个网络里的点的编号
struct node{
int u,v,com;
}e[N];
int iden;//点的编号
void Init()
{
while(!Q.empty())
Q.pop();
memset(d,0x7f,sizeof(d));
}
void dijkstra()
{
Init();
d[s]=0;Q.push(make_pair(0,s));
while(!Q.empty())
{
pair<LL,int> tmp=Q.top();
Q.pop();
int u=tmp.second;
if(tmp.first>d[u]) continue;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i].first; LL w=G[u][i].second;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
Q.push(make_pair(d[v],v));
}
}
}
}
int ID(int x,int y)
{
if(mp.find(make_pair(x,y))!=mp.end())
return mp[make_pair(x,y)];
return mp[make_pair(x,y)]=++iden;
}
int main()
{
n=rd(),m=rd();
for(int i=1;i<=m;i++)
{
int u=rd(),v=rd(),id=rd();
if(!c[id]) c[id]=++tot;
e[i].u=u,e[i].v=v,e[i].com=c[id];
}
iden=n;
for(int i=1;i<=m;i++)
{
int u=ID(e[i].u,e[i].com),v=ID(e[i].v,e[i].com);
G[u].push_back(make_pair(v,0));
G[v].push_back(make_pair(u,0));
G[e[i].u].push_back(make_pair(u,1));
G[u].push_back(make_pair(e[i].u,1));
G[e[i].v].push_back(make_pair(v,1));
G[v].push_back(make_pair(e[i].v,1));
}
s=1;
dijkstra();
if(d[n]>=INF) puts("-1");
else printf("%lld\n",d[n]/2);
return 0;
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com