题意:
给定一个带权有向图,要求回答询问,在经过节点数不超过 s 的条件下,问从
S 到 T 的最短路径!数据范围:
N(2≤N≤100),M(0≤M≤1000),Q(1≤Q≤10)
思路:
因为对中途经过的节点数有限制,所以得记录下这一信息!
直接对图进行一遍 dfs , dp[u][i] 表示目前在节点 u ,已经经过了i 个城市,对 u−>v 边,转移就是:
for(int j=1;j<=n;j++) {
if(dp[u][j] != -1) {
if(dp[v][j+1] == -1) dp[v][j+1] = dp[u][j] + e[i].w;
else dp[v][j+1] = min(dp[v][j+1],dp[u][j] + e[i].w);
}
}
但是这样话T, dfs 一次的复杂度是 O(n∗m) ,这尼玛居然T了,正解是SPFA,复杂度接近 O(m) ,相比原来的解法就是加入了队列优化,用当前最优最松弛其它点!
代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <string>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int N=5+1e2,MOD=7+1e9;
int n,dp[N][N];
char city[25],s1[25],s2[25];
map<string,int> mp;
int tot,head[N];
struct edge
{
int to,w,next;
}e[1005];
bool vis[N][N];
void init()
{
tot=0;
mp.clear();
memset(head,-1,sizeof(head));
memset(dp,INF,sizeof(dp));
}
void addedge(int u,int v,int c)
{
e[tot].to = v,e[tot].w = c,e[tot].next = head[u],head[u] = tot++;
}
void dfs(int u)
{
for(int i=head[u];i!=-1;i=e[i].next) {
int v=e[i].to;
for(int j=1;j<=n;j++) {
if(dp[u][j] != -1) {
if(dp[v][j+1] == -1) dp[v][j+1] = dp[u][j] + e[i].w;
else dp[v][j+1] = min(dp[v][j+1],dp[u][j] + e[i].w);
}
}
dfs(v);
}
}
void SPFA()
{
dp[1][1]=0;
memset(vis,0,sizeof(vis));
queue<P> q;
q.push(MP(1,1));
vis[1][1]=1;
while(!q.empty()) {
int u = q.front().FT , cnt = q.front().SD;
q.pop(); vis[u][cnt]=0;
for(int i=head[u];i!=-1;i=e[i].next) {
int v=e[i].to;
if(dp[v][cnt+1] > dp[u][cnt] + e[i].w) {
dp[v][cnt+1] = dp[u][cnt] + e[i].w;
if(!vis[v][cnt+1]) {
vis[v][cnt+1]=1;
q.push(MP(v,cnt+1));
}
}
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T,ca=0;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init();
for(int i=1;i<=n;i++) {
scanf("%s",city);
mp[city]=i;
}
int c,m; scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%s%s%d",s1,s2,&c);
addedge(mp[s1],mp[s2],c);
}
SPFA();
for(int i=1;i<=n;i++) {
dp[n][i]=min(dp[n][i-1],dp[n][i]);
}
printf("Scenario #%d\n",++ca);
int Q;
scanf("%d",&Q);
while(Q--){
int q;
scanf("%d",&q);
q = min(n,q+2);
if(dp[n][q] == INF) {
printf("No satisfactory flights\n");
}
else printf("Total cost of flight(s) is $%d\n",dp[n][q]);
}
if(T) puts("");
}
//system("pause");
return 0;
}