这个题有两种路径,普通线和商务线。而且告诉我们商务线就只能用一次,那很显然枚举就行。枚举每一条商务线,看能否更新最短路就行。我们从起点终点分别出发跑最短路,如果起点到商务线一个端点的最短距离加上终点到商务线另一个端点最短距离再加上商务线距离之和可以更新现有最短路,则更新最短路。枚举下去就行,复杂度为O(t * k * mlogn),其中t为数据组数,k为商务线数,m、n分别为边数和点数。
参考代码:
#include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<algorithm> #include<iostream> #include<stack> #define inf 1e9 using namespace std; #define N 510 #define M 2010 int head[N],nxt[M],to[M],val[M],dis[M],dist[M],path[N],patht[N]; int n,m,k,s,t,cnt; void add(int u,int v,int w) { nxt[++cnt] = head[u]; head[u] = cnt; val[cnt] = w; to[cnt] = v; } struct node { int u,dis; bool operator < (const node &a) const { return dis > a.dis; } }top,qwq; void dijkstra(int str) { priority_queue<node>q; memset(path,0,sizeof(path)); for(int i = 1;i <= n;i++) dis[i] = inf; dis[str] = 0; top.u = str; top.dis = 0; q.push(top); while(!q.empty()) { top = q.top(); q.pop(); int u = top.u; for(int i = head[u];i;i = nxt[i]) { int v = to[i]; if(dis[v] > dis[u] + val[i]) { path[v] = u; dis[v] = dis[u] + val[i]; qwq.u = v; qwq.dis = dis[v]; q.push(qwq); } } } } void dfs(int u)//枚举前驱输出路径 { if(u == s) { printf("%d",u); return; } dfs(path[u]); printf(" %d",u); } void dfst(int u) { printf(" %d",u); if(u == t) return; dfst(patht[u]); } int main() { int flag = 0; while(scanf("%d %d %d",&n,&s,&t) != EOF) { if(flag) printf(" "); memset(head,0,sizeof(head)); cnt = 0; scanf("%d",&m); for(int i = 1;i <= m;i++) { int x,y,z; scanf("%d %d %d",&x,&y,&z); add(x,y,z); add(y,x,z); } dijkstra(t); for(int i = 1;i <= n;i++) { dist[i] = dis[i]; patht[i] = path[i]; } dijkstra(s); scanf("%d",&k); int ss = 0,tt = 0,ans = dis[t]; while(k--) { int u,v,w; scanf("%d %d %d",&u,&v,&w); if(dis[u] + dist[v] + w < ans) { ans = dis[u] + dist[v] + w; ss = u; tt = v; } if(dist[u] + dis[v] + w < ans) { ans = dist[u] + dis[v] + w; ss = v; tt = u; } } if(ss != 0)//看最短路是否被更新 { dfs(ss); dfst(tt); printf(" %d %d ",ss,ans); } else { dfs(t); printf(" Ticket Not Used %d ",ans); } flag++; } }