题意:给你一个普通的无向带权图,再给你一个vip无向带权图,给你起点终点,要求普通图随便走,vip图只能走一条边,求起点到终点的最短路。
思路:vip图最多k=1000条边,如果枚举每条边并将其加入普通图求最短路,复杂度太高,可以这样想,先从起点求到每个点的最短路并用 g 数组保存,再从终点求每个点的最短路并用 f 数组保存,假如u,v是vip的一条路,那么ans=min(ans, dist(u,v)+g[u]+f[v], dist(u,v)+g[v]+f[u]),这样的话,总复杂度就是两次最短路的复杂度+k。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn=500+5;
const int inf=1e8;
struct node
{
int u,v,dist;
bool friend operator<(node c,node d)
{
return c.dist>d.dist;
}
}a[1000+5],no,ne;
vector<int>G[maxn],dis[maxn];
int pre1[maxn],pre2[maxn],g[maxn],f[maxn],vis[maxn];
int n,ans;
void init()
{
for(int i=0;i<=n;i++)
{
G[i].clear();
dis[i].clear();
pre1[i]=pre2[i]=0;
}
}
void dij(int s,int e,int d[501],int pre[501],int flag)
{
no.u=s;
no.dist=0;
priority_queue<node>q;
q.push(no);
for(int i=0;i<=n;i++)
{
vis[i]=pre[i]=0;
d[i]=inf;
}
d[s]=0;
while(!q.empty())
{
no=q.top();q.pop();
int u=no.u;
//d[u]=no.dist;
if(u==e)
ans=no.dist;
if(vis[u])
continue;
vis[u]=1;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(d[v]>d[u]+dis[u][i])
{
pre[v]=u;
d[v]=no.dist+dis[u][i];
ne.u=v;
ne.dist=d[v];
q.push(ne);
}
}
}
if(flag==1)
{
for(int i=1;i<=n;i++)
g[i]=d[i],pre1[i]=pre[i];
}
else
{
for(int i=1;i<=n;i++)
f[i]=d[i],pre2[i]=pre[i];
}
}
void print1(int u,int e)
{
if(u!=e)
{
print1(pre1[u],e);
printf(" %d",u);
}
else
printf("%d",u);
}
void print2(int u,int e)
{
if(u!=e)
{
printf("%d ",u);
print2(pre2[u],e);
}
else
printf("%d\n",u);
}
void work(int k,int s,int e)
{
int flag1,flag2;
flag1=flag2=0;
for(int i=1;i<=k;i++)
{
int u=a[i].u;
int v=a[i].v;
int dist=a[i].dist;
if(g[u]+f[v]+dist<ans)
{
ans=g[u]+f[v]+dist;
flag1=u,flag2=v;
}
if(g[v]+f[u]+dist<ans)
{
ans=g[v]+f[u]+dist;
flag1=v,flag2=u;
}
}
if(!flag1)
{
print1(e,s);
printf("\n");
printf("Ticket Not Used\n");
}
else
{
print1(flag1,s);
printf(" ");
print2(flag2,e);
printf("%d\n",flag1);
}
printf("%d\n",ans);
}
int main()
{
int s,e,kase=0;
while(~scanf("%d%d%d",&n,&s,&e))
{
int i,m,k,u,v,z;
if(kase++>0)
printf("\n");
init();
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&u,&v,&z);
G[u].push_back(v);
G[v].push_back(u);
dis[u].push_back(z);
dis[v].push_back(z);
}
scanf("%d",&k);
for(i=1;i<=k;i++)
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].dist);
dij(s,e,g,pre1,1);
dij(e,s,f,pre2,2);
work(k,s,e);
}
}