题目传送门
【题目大意】
【思路分析】
看到问题要求“最少”,于是理所当然地想到DP啦。
设$f[i][j][k]$表示从$i$城到$j$城,途中换了$k$次车所需的最小时间,然后可以想到转移方程:
$$f[i][j][k]=min(f[i][j][k],min\{f[i][t][k-1]+f[t][j][0]\}(1\le t\le n))$$
我们要预处理出$f[i][j][0]$,即$m$种车中从$i$城到$j$城所需的最短时间。我们记$w[i][j][k]$为第$i$种车从$j$城到$k$城所需的最短时间,则$w[i][j][k]=min\{w[i][j][t]+w[i][t][k]\}(1\le t\le n)$,然后可得$f[j][k][0]=min\{w[i][j][k]\}(1\le i\le m)$。
初始值:$w$读入,$f$无穷大。
答案:$min\{f[s][t][i]\}(0\le i\le k)$
代码实现过程中要注意循环的嵌套顺序!
【代码实现】
1 #include2 #include 3 #include 4 #include 5 #include 6 #define g() getchar() 7 #define rg register 8 #define go(i,a,b) for(rg int i=a;i<=b;i++) 9 #define back(i,a,b) for(rg int i=a;i>=b;i--) 10 #define db double 11 #define ll long long 12 #define il inline 13 #define pf printf 14 #define sf scanf 15 #define mem(a,b) memset(a,b,sizeof(a)) 16 using namespace std; 17 int fr(){ 18 int w=0,q=1; 19 char ch=g(); 20 while(ch<'0'||ch>'9'){ 21 if(ch=='-') q=-1; 22 ch=g(); 23 } 24 while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g(); 25 return w*q; 26 } 27 const int N=52; 28 const ll INF=1e10+999999999; 29 int n,m,r; 30 ll f[N][N][N],w[N][N][N],ans; 31 int main(){ 32 //freopen("","r",stdin); 33 //freopen("","w",stdout); 34 while(sf("%d%d%d",&n,&m,&r)!=EOF){ 35 mem(f,63); 36 go(i,1,m) go(j,1,n) go(k,1,n) w[i][j][k]=fr(); 37 //按照输入顺序嵌套循环 38 go(i,1,m) go(t,1,n) go(j,1,n) go(k,1,n) 39 w[i][j][k]=min(w[i][j][k],w[i][j][t]+w[i][t][k]); 40 //以t为中间点找最小值,Floyd最短路 41 go(j,1,n) go(k,1,n) go(i,1,m) 42 f[j][k][0]=min(f[j][k][0],w[i][j][k]); 43 //对于固定的两个城市j,k,枚举m种车旭找最短时间 44 go(k,1,n) go(t,1,n) go(i,1,n) go(j,1,n) 45 f[i][j][k]=min(f[i][j][k],f[i][t][k-1]+f[t][j][0]); 46 //DP,注意循环嵌套的顺序! 47 while(r--){ 48 rg int s=fr(),t=fr(),k=fr(); 49 if(k>n) k=n;ans=INF; 50 go(i,0,k) ans=min(ans,f[s][t][i]); 51 pf("%lld\n",ans); 52 } 53 } 54 return 0; 55 }