• Mr. Rito Post Office [Aizu-2200] [图论] [DP]


    题意:
    你是某个岛国(ACM-ICPC Japan )上的一个苦逼程序员,你有一个当邮递员的好基友利腾桑遇到麻烦了:全岛有一些镇子通过水路和旱路相连,走水路必须要用船,在X处下船了船就停在X处。而且岛上只有一条船,下次想走水路还是得回到X处才行;两个镇子之间可能有两条以上的水路或旱路;邮递员必须按照清单上的镇子顺序送快递(镇子可能重复,并且对于重复的镇子不允许一次性处理,比如ABCB的话B —定要按顺序走两次才行)。
    测试数据有多组:
    N M
    xl yl tl sll
    x2 y2 t2 sl2
    XM yM tM SIM
    R
    Zl Z2 ... ZR
    N (2 <= N <= 200)是镇子的数星,M (1 <= M <= 10000)是旱路和水路合计的数量。
    从第2行到第M+1行是路径的描述,路径连接xi yi两地,路径花费ti (1 s ti s 1000)时间,sli为L时表示是旱路,S时表示是水路。
    可能有两条及以上路径连接两个镇子,并且路径都是双向的。
    M + 2行的R是利腾需要去的镇子的数量,M + 3是利腾需要去的镇子的编号
    初始状态利腾和船都在第一个镇子,且肯定有方法达到需要去的镇子。
    测试数据为0 0的时候表示终止。

    样例输入

    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

    样例输出

       18

       269

    分析

    这道dp题还是比较容易想的,不过有一个坑人的地方!

    因为要转移的参考量,一是当前位置,二是船的位置,那么设dp[i][j]为走到第i个城市,船停在j

    那么状态转移方程就是dp[i][j]=min(dp[i-1][k]+l[id[i-1]][k]+s[k][j]+l[j][id[i]],dp[i][j]);

    但是j==k的时候,不要去移船!dp[i][j]=min(dp[i-1][k]+l[id[i-1][id[i]],dp[i][j]);

    代码

     1 #include<set>
     2 #include<map>
     3 #include<queue>
     4 #include<stack>
     5 #include<cmath>
     6 #include<cstdio>
     7 #include<cstring>
     8 #include<iostream>
     9 #include<algorithm>
    10 #define RG register ll
    11 #define rep(i,a,b)    for(RG i=a;i<=b;++i)
    12 #define per(i,a,b)    for(RG i=a;i>=b;--i)
    13 #define ll long long
    14 #define inf (1<<29)
    15 #define maxn 205
    16 #define maxr 1005
    17 using namespace std;
    18 ll n,m,cnt;
    19 ll l[maxn][maxn],s[maxn][maxn],id[maxr],dp[maxr][maxn];
    20 inline ll read()
    21 {
    22     ll x=0,f=1;char c=getchar();
    23     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    24     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    25     return x*f;
    26 }
    27 
    28 void DP()
    29 {
    30     memset(dp,63,sizeof(dp));
    31     dp[1][id[1]]=0;
    32     rep(i,2,cnt)
    33         rep(j,1,n)
    34             rep(k,1,n)
    35             {
    36                 if(j!=k) //
    37                     dp[i][j]=min(dp[i-1][k]+l[id[i-1]][k]+s[k][j]+l[j][id[i]],dp[i][j]);
    38                 else
    39                     dp[i][j]=min(dp[i-1][k]+l[id[i-1]][id[i]],dp[i][j]);
    40             }
    41     ll mn=inf;
    42     rep(i,1,n)    mn=min(mn,dp[cnt][i]);
    43     cout<<mn<<endl;
    44 }
    45 
    46 int main()
    47 {
    48     char opt;
    49     while(1)
    50     {
    51         n=read(),m=read();
    52         if(!n)    return 0;
    53         rep(i,1,n)rep(j,1,n)    l[i][j]=s[i][j]=inf;
    54         rep(i,1,n)                l[i][i]=s[i][i]=0;
    55         for(RG i=1,a,b,c;i<=m;i++)
    56         {
    57             a=read(),b=read(),c=read();opt=getchar();
    58             if(opt=='L')    l[a][b]=l[b][a]=c;
    59             else            s[a][b]=s[b][a]=c;
    60         }
    61         rep(k,1,n)rep(i,1,n)rep(j,1,n)    l[i][j]=min(l[i][j],l[i][k]+l[k][j]),s[i][j]=min(s[i][j],s[i][k]+s[k][j]);
    62         cnt=read();
    63         rep(i,1,cnt)    id[i]=read();
    64         DP();
    65     }
    66     return 0;
    67 }
    View Code
  • 相关阅读:

    决斗(Headshot )
    密码(Password)
    线性表
    hdu 5409 CRB and Graph(边双联通分量)
    无向图的边双连通分量(EBC)
    hdu 3461 Code Lock 并查集(有点难想到)★★
    hdu 1558 Segment set 计算几何+并查集★
    交表(Send a Table)
    杨辉三角与二项式定理
  • 原文地址:https://www.cnblogs.com/ibilllee/p/9239869.html
Copyright © 2020-2023  润新知