题解:游历的路线”

Description
      我们的郭嘉大大经过一段时间发现了袁绍这个人干大事而惜身,见小利而忘义,又逢曹操在招兵买马,决定逃离袁绍去投曹操,而我们的曹操在第M天招募良材,我们的郭嘉大大既不能早去,也不能晚去,于是乎,他就趁着这一段时间到其他的城市游历一番,而每两个城市之间只能坐马车来往,由于我们的郭嘉大大很贪钱,他想用最少的费用,所以需要我们帮他求出这一个最小的费用。
 
 
Input
  第一行包含两个数n,m, 表示有n个城市,和m天后曹操招纳良材。城市一就是郭嘉所在的城市,城市n就是曹操处。接下来n * (n – 1)行描述马车乘坐表。   第2到第n行就是描述的城市1到2… n的马车乘坐表.   第n + 1到第2n-1行描述的城市2到城市1,3..n的马车乘坐表… … 对每一行,首先有一个数T,表示城市I到城市J的马车以T为周期,接下来有T个数,表示每天的马车的价格,如果价格为0则表示没有马车可坐。(n <= 100, m <= 200, T <= 20, Price <= 50000)
Output
  如果存在这样的路线使郭嘉第m天到达曹操处,则输出最少的费用,否则输出0!
 
Sample Input
3 5                                       
2 130 150
3 75 0 80
2 110 100
4 60 70 60 50
3 0 135 140
2 70 80
Sample Output
355
 
题目的意思就是说,给你n个点,每个点可以到达其它所有的点,到达其它点需要花钱,每两点之间有一个周期,每两个点之间的花费成周期性的变化。我们要求的是从点1在第m天时到点n的最小花费,如果不能在第m天时到达点n,则无解,输出0。
这道题稍微想一下就可以想到动态规划,比赛时我想到了但没打出来,我们定义一个数组t[i][j],表示城市i到j的周期;一个数组w[i][j][k]表示城市i到j周期中第k个周期所需要的花费(如果是0则无法到达);一个变量c表示现在是周期中的第c个周期;f[i][j]第i天从城市1到j所需要的最小花费;用三个for循环,第一层枚举天数i,第二层枚举城市j,第三层枚举城市k,状态转移方程就是f[i][j]=min(f[i][j],f[i-1][k]+w[k][j][c]),结果就是f[m][n]。但这样还不够,因为有可能有写点在第i天的时候刚好不能到达其它的一个点,所以我们给f[i][j]的初始值全部附为-1,当f[i-1][k]=-1时,跳过这一次循环,因为这说明第i-1天无法从城市1到k,判断完这个后,如果f[i][j]=-1,直接f[i][j]=f[i-1][k]+w[k][j][c],因为f[i][j]=-1表示还没有走过,并不是不能到达,因为这之前已经判断过了,如果不能到达就已经跳出了循环,不会到这一步。还有给f[i][j]的初始值附为-1后,要再把f[0][1]=0,表示第0天到城市1用了0元,这样才能计算出正确答案,否则如果没有这个语句,f[0][1]=-1就表示第0天到城市1用了-1元,错误了。
附上代码:
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 int m,n,o;
 6 int f[300][300];
 7 int t[300][300];
 8 int w[300][300][25];
 9 void read();
10 void solve();
11 int main()
12 {
13     read();
14     solve();
15     printf("%d",f[m][n]);
16     return 0;
17 }
18 void solve()
19 {
20     for(int i=1;i<=m;i++)
21     for(int j=1;j<=n;j++)
22     for(int k=1;k<=n;k++)
23     {
24         if(j==k) continue;        
25         int c=i;
26         if(c%t[k][j]!=0) c%=t[k][j];
27         else c=t[k][j];    
28         if(w[k][j][c]==0) continue;
29         if(f[i-1][k]==-1) continue;
30         if(f[i][j]==-1) f[i][j]=f[i-1][k]+w[k][j][c];    
31         f[i][j]=min(f[i][j],f[i-1][k]+w[k][j][c]);
32     }
33 }
34 void read()
35 {
36     scanf("%d%d",&n,&m);
37     for(int i=1;i<=n;i++)
38     for(int j=1;j<=n;j++)
39     {
40         if(i==j) continue;
41         scanf("%d",&t[i][j]);
42         for(int k=1;k<=t[i][j];k++)
43         scanf("%d",&w[i][j][k]);
44     }
45     memset(f,-1,sizeof(f));
46     f[0][1]=0;
47 }

                                                                                                                                                                                                                                                                                         by:ルオ・テンイの锦依卫

                                                                                                                                                                                                                                                                                         未经作者允许,禁止转载!

 

转载于:https://www.cnblogs.com/grt-lty-love-forever/p/10335996.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值