zoukankan      html  css  js  c++  java
  • [ZJOI2006] 物流运输

    题目链接:https://www.luogu.org/problemnew/show/P1772

    DP套最短路。

    还是蒟蒻做题少。。。开始想的是状压DP。。但是因为太蒻了,不会很高效地处理一些点集的最短路,弄了一个T飞的算法。之后看了题解才知道原来是可以用DP套最短路做的。。。。。

    为什么需要DP?因为本题涉及到状态的选择。每一天要么不更换线路,要么更换。显然这个东西是没有办法贪心搞的,所以只能用DP把状态整合起来计算。

    我们设状态(f[i])为第(i)天的最小花费,(dist[i][j])为第(i)天到第(j)天选择同一条路径的花费。

    那么状态转移方程是:

    [f[i]=min(f[i],f[j]+dist[j+1][i] imes (i-j)+k ]

    其中:((0<=j<i))

    注意需要用位运算预先处理一下第(i)到第(j)天的非法点,在spfa(当然也可以dij)求最短路的时候不要走这些非法点。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<bitset>
    #define MAXN 110
    using namespace std;
    int n,m,k,e,d,edge_number;
    int head[MAXN],done[MAXN],dis[MAXN],dist[MAXN][MAXN],f[MAXN],dp[MAXN];
    bitset<21>shut[MAXN],off[MAXN][MAXN];
    struct Edge{int nxt,to,dis;}edge[MAXN*MAXN];
    inline void add(int from,int to,int dis)
    {
        edge[++edge_number].dis=dis;
        edge[edge_number].to=to;
        edge[edge_number].nxt=head[from];
        head[from]=edge_number;
    }
    inline void spfa(int from,int to)
    {
        queue<int>q;
        for(int i=1;i<=m;i++) dis[i]=0x3f,done[i]=0;
        q.push(1); done[1]=1; dis[1]=0;
        while(!q.empty())
        {
            int u=q.front();
            q.pop(); done[u]=0; 
            for(int i=head[u];i;i=edge[i].nxt)
            {
                int v=edge[i].to;
                if(off[from][to][v-1]==1) continue;
                if(dis[v]>dis[u]+edge[i].dis)
                {
                    dis[v]=dis[u]+edge[i].dis;
                    if(!done[v])
                    {
                        done[v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
    int main()
    {
        memset(f,0x3f,sizeof(f));
        memset(dist,0x3f,sizeof(dist));
        scanf("%d%d%d%d",&n,&m,&k,&e);
        for(int i=1;i<=e;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }	
        scanf("%d",&d);
        for(int i=1;i<=d;i++)
        {
            int p,a,b;
            scanf("%d%d%d",&p,&a,&b);
            for(int j=a;j<=b;j++)
                shut[j][p-1]=1;
        }
        for(int i=1;i<=n;i++)
        {
            off[i][i]=shut[i];
            for(int j=i+1;j<=n;j++)
                off[i][j]=off[i][j-1]|shut[j];
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
            {
                spfa(i,j);
                dist[i][j]=dis[m];
            }
        }
        f[0]=0;
        f[1]=dist[1][1];
        for(int i=2;i<=n;i++)
            for(int j=0;j<i;j++)
                f[i]=min(f[i],f[j]+dist[j+1][i]*(i-j)+(j==0?0:k));
        printf("%d
    ",f[n]);
        return 0;
    }
    
  • 相关阅读:
    Xcode4快速Doxygen文档注释 — 简明图文教程(3分钟后爽歪歪)
    ACE小记
    【C++】获得本机所有网卡的IP和MAC地址信息(转)
    一周好文(11)
    cocos2d‘s replaceScene
    iPhone 真机调试安装流程
    金牌银牌铜牌
    整数分割(摘抄)

    马拦过河卒
  • 原文地址:https://www.cnblogs.com/fengxunling/p/9871886.html
Copyright © 2011-2022 走看看