ZOJ 1232

来源:互联网 发布:美国衰落 知乎 编辑:程序博客网 时间:2024/05/16 11:10
题目意思很简单:
有A个村子和B个城堡,村子标号是1~A,城堡标号是A+1~B。马里奥现在位于城堡B,他要带公主回到村子1,他有一双靴子,穿上之后可以不用时间就能从一个地方飞到另外一个地方,但是穿着靴子不能穿过城堡,穿靴子的次数也不能超过 K 次,一次不能超过 L km。求从 B 到 1 所用的最短时间。
分析:
最开始是在一本书上看到这道题目,说是Dijstra,于是打算来写写看。结果悲剧了。题目的关键点其实是在哪里使用鞋子才能使得全局的时间最少,可以用 DP 来解决,用一种逆向思维,先来写动态转移方程,用 i 来表示目前到了 i 点,用 j 来表示到 i 点时穿了几次靴子,dp[i][j] = min{dp[k][j-1],dp[k][j]+map[k][i]} 从方程中可以看出,需要知道任意两个点之间的距离,也需要知道任意两个点之间是否能够穿靴子通过(比如考虑到 K,L),此时就需要用到求最短路径了,由于此时用到的是任意两个点之间的最短路径,所以最好用 Floyd ,用 Dijstra 的话在求任意两个点之间是否能够穿靴子通过时就会出现点小麻烦。
好吧,其实我两种都写了。

贴下Dijstra的代码

#include<stdio.h>const int maxn = 150;const int INF = 1000000000;int mat[maxn][maxn],tmp[maxn][maxn],Dist[maxn];int DP[maxn][20],newmat[maxn][maxn];bool visited[maxn];int n,A,B,L;void Dijstra(int s){int i,j,k,min;for(i=1;i<=n;i++){Dist[i] = mat[s][i];visited[i] = false;}Dist[s] = 0;visited[s] = true;for(i=1;i<=n;i++){k = -1;min = INF;for(j=1;j<=n;j++)if(visited[j]==false&&min>Dist[j]){k = j;min = Dist[j];}if(k!=-1){visited[k] = true;for(j=1;j<=n;j++){if(Dist[k]+mat[k][j]<Dist[j]){Dist[j] = Dist[k] + mat[k][j];}}}}}void Dijstra1(int s)//为了求tmp[][],tmp[][]保存的是任意两点是否能穿鞋子通过。{int i,j,k,min;for(i=1;i<=n;i++){Dist[i] = mat[s][i];visited[i] = false;}Dist[s] = 0;visited[s] = true;for(i=1;i<=n;i++){k = -1;min = INF;for(j=1;j<=n;j++)if(visited[j]==false&&min>Dist[j]){k = j;min = Dist[j];}if(k!=-1){visited[k] = true;for(j=1;j<=n;j++){if(Dist[k]+mat[k][j]<Dist[j]&&k<=A){Dist[j] = Dist[k]+mat[k][j];if(Dist[j]<=L)tmp[s][j] = 0;}}}}}int main(){int i,j,t,m,K;scanf("%d",&t);while(t--){scanf("%d%d%d%d%d",&A,&B,&m,&L,&K);n = A+B;for(i=1;i<=n;i++)for(j=1;j<=n;j++)mat[i][j] = newmat[i][j] = tmp[j][i] = INF;//初始化int a,b,c;for(i=0;i<m;i++){scanf("%d%d%d",&a,&b,&c);mat[a][b] = mat[b][a] = c;if(c<=L)tmp[a][b] = tmp[b][a] = 0;newmat[a][b] = newmat[b][a] = c;}//构图for(i=1;i<=n;i++){Dijstra1(i);Dijstra(i);for(j=1;j<=n;j++)newmat[i][j] = Dist[j];}for(i=1;i<=n;i++)DP[i][0] = newmat[1][i];//未使用加速靴时的时间for(j=1;j<=K;j++)DP[1][j] = 0;    for(i=2;i<=n;i++){for(j=1;j<=K;j++){int min = INF,tt;for(int l = 1;l<i;l++){if(!tmp[l][i])tt = DP[l][j-1]>DP[l][j]+newmat[l][i]?DP[l][j]+newmat[l][i]:DP[l][j-1];else tt = newmat[l][i]+DP[l][j];if(tt<min)min = tt;}DP[i][j] = min;}}printf("%d\n",DP[n][K]);}return 0;}
再来比对一下Floyd的代码
#include<stdio.h>const int maxn = 150;const int INF = 1000000000;int dp[maxn][20],mat[maxn][maxn],mind[maxn][maxn],tmp[maxn][maxn];int n,A,B,L;void Floyd(){int i,j,k;for(i=1;i<=n;i++)for(j=1;j<=n;j++)mind[i][j] = mat[i][j];for(k=1;k<=n;k++){for(i=1;i<=n;i++){for(j=1;j<=n;j++){if(mind[i][k]+mind[k][j]<mind[i][j]){mind[i][j] = mind[i][k] + mind[k][j];if(k<=A&&mind[i][j]<=L)tmp[i][j] = 1;}}}}}int main(){int t,K,m,i,j,a,b,c;scanf("%d",&t);while(t--){scanf("%d%d%d%d%d",&A,&B,&m,&L,&K);n = A+B;for(i=1;i<=n;i++){for(j=1;j<=n;j++){if(i==j)mat[i][j] = 0;elsemat[i][j] = INF;tmp[i][j] = 0;}}//初始化for(i=1;i<=m;i++){scanf("%d%d%d",&a,&b,&c);mat[a][b] = mat[b][a] = c;if(c<=L)tmp[a][b] = tmp[b][a] = 1;}//初步构图Floyd();//mind[][]保存计算之后的最短路径for(i=1;i<=n;i++)dp[i][0] = mind[1][i];for(i=1;i<=K;i++)dp[1][i] = 0;for(i=2;i<=n;i++){for(j=1;j<=K;j++){int min = INF,tt;for(int l=1;l<i;l++){if(tmp[l][i])tt = dp[l][j-1]<dp[l][j]+mind[l][i]?dp[l][j-1]:dp[l][j]+mind[l][i];elsett = dp[l][j] + mind[l][i];if(tt<min)min = tt;}dp[i][j] = min;}}printf("%d\n",dp[n][K]);}return 0;}



原创粉丝点击