dp+最短路——Mr. Rito Post Office(Aizu - 2200 )

dp+最短路

——Mr. Rito Post Office(Aizu - 2200 )
在一些城市中有水路和陆路连接,每一条路都有长度。但是水路必须乘船,且坐船到达某个位置后船必须留在那里,下次坐必须回到该地。现在有m城市要到达,且必须按照指定的顺序,问最小代价。
Sample Input
3 3
1 2 5 L
1 2 7 S
2 3 11 S
3
1 2 3
5 5
1 2 15 L
2 3 10 L
4 5 7 L
1 3 30 S
3 4 100 S
5
1 3 5 4 1
0 0
Output for the Sample Input
18
269

解析:首先用floyd-warshall算法将每两个点之间的最短陆路和水路路径求出。
再者,(下面万年不会的dp了)dp[i][j]=在第i个城市的时候,将船停靠在j这个时候所需要的最小花费。
转移方程:
1.就是当前一步通过陆路来走
dp[i][j]=min(dp[i][j],dp[i-1][j]+land[d[i-1]][d[i]]);
2.这一种就是中间有使用过水路,并且把船停在了k号位置上,再从陆路走到当前城市。(这里注意水路不是仅仅一步从上一个城市走到当前城市,而是中间有用过水路)
for(int k=1;k<=n;k++){ dp[i][k]=min(dp[i][k] ,
dp[i-1][j]+land[d[i-1]][j]+water[j][k]+land[k][d[i]]); }
3.最后答案是,再最后一个城市的时候,船停在任意一个城市的最小值。
注意点:1.使用LL
2.初始化dp时,第一步虽然你也可以什么都不用走,但是你可以将船放到任意点上,你再走回来哦!
3.这里边双向,并且输入边可能重复,所以取最小的。

#include<cstdio>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
long long water[400][400],land[400][400],dp[2000][400];
int n,m,p,a,b,d[2000];
long long c;
char s1,s2;
void floyd()
{
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
               water[j][k]=min(water[j][k],water[j][i]+water[i][k]);
               land[j][k]=min(land[j][k],land[j][i]+land[i][k]);
            }
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m)&&n)
    {
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i==j){
                    water[i][j]=0;land[i][j]=0;continue;
                }
                water[i][j]=inf;
                land[i][j]=inf;

            }
        }
        for(int i=0;i<m;i++){
            scanf("%d%d%lld%c%c",&a,&b,&c,&s1,&s2);
            if(s2=='S') {
                    water[a][b]=min(c,water[a][b]);
                    water[b][a]=water[a][b];
            }
            else {
                    land[a][b]=min(land[a][b],c);
                    land[b][a]=land[a][b];
            }
        }
        floyd();
        scanf("%d",&p);
        for(int i=0;i<p;i++){
            scanf("%d",&d[i]);
        }
        for(int i=0;i<p;i++) for(int j=1;j<=n;j++) dp[i][j]=inf;

        for(int i=1;i<=n;i++) dp[0][i]=water[d[0]][i]+land[i][d[0]];
        for(int i=1;i<p;i++){
            for(int j=1;j<=n;j++){
                dp[i][j]=min(dp[i][j],dp[i-1][j]+land[d[i-1]][d[i]]);
                for(int k=1;k<=n;k++){
                    dp[i][k]=min(dp[i][k],dp[i-1][j]+land[d[i-1]][j]+water[j][k]+land[k][d[i]]);
                }
            }
        }
       long long ans=inf;
        for(int i=1;i<=n;i++){
            ans=min(ans,dp[p-1][i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值