zoukankan      html  css  js  c++  java
  • bzoj 1003物流运输 区间dp+spfa

    基本思路:

    一开始确实没什么思路,因为觉得怎么着都会超时,然后看一下数据范围,呵,怎么都不会超时。

    思路:

    1.看到能改变线路,想到可以用以下区间dp,区间dp的话,先枚举长度,枚举开始位置,然后枚举中间点 dp[i][j]=min(dp[i][j],dp[i][z]+dp[z][j]+k);

    2.然后每段时间最短路究竟是多少,然后因为不会超时,所以就二重循环枚举就好了

    (ps:这里要说明一下给自己提个醒:

      spfa就是队列优化的迪杰斯特拉,然后的话vis数组每次出一个就置零一个,如果不置零是错的

      堆优化的迪杰斯特拉自己之前也加vis,而且每次出一个的话不置零,不会错,因为vis数组是不必要的

      所以以后写的话一般就写spfa好了,堆优化的迪杰斯特拉的话略难写一点,而且两者速度也差不多

      普通的迪杰斯特拉的话还是要置零的,因为比起spfa就是优化在了队列

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<queue>
    
    using namespace std;
    
    typedef long long ll;
    
    const int inf = 0x3f3f3f3f;
    const int maxn = 100+10;
    
    int head[maxn],cnt;
    struct Edge{
        int to,val,next;
    }edge[maxn<<4];
    ll tim[maxn][maxn],f[maxn][maxn];
    bool flag[maxn][maxn],block[maxn],vis[maxn];
    int dis[maxn];
    int n,m,k;
    
    void add(int u,int v,int w){
        edge[cnt].to=v;
        edge[cnt].val=w;
        edge[cnt].next=head[u];
        head[u]=cnt++;
    }
    int spfa(int s,int e){
        memset(block,false,sizeof(block));
        memset(vis,false,sizeof(vis));
        memset(dis,inf,sizeof(dis));
        queue<int>q;
        q.push(1);vis[1]=true;dis[1]=0;
        for(int i=s;i<=e;i++){
            for(int j=1;j<=m;j++){
                if(flag[i][j]){
                    block[j]=true;
                }
            }
        }
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=head[u];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                int w=edge[i].val;
                if(!block[v]&&dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    if(!vis[v]){
                        vis[v]=true;
                        q.push(v);
                    }
                }
            }
            vis[u]=false;
        }
        return dis[m];
    }
    void dp(){
        for(int l=1;l<=n;l++){
            for(int s=1;s<=n;s++){
                int e=s+l-1;
                if(e>n) continue;
                f[s][e]=(ll)tim[s][e]*(e-s+1);
                for(int z=s;z<e;z++){
                    f[s][e]=min(f[s][e],f[s][z]+k+f[z+1][e]);
                }
            }
        }
    }
    int main(){
        memset(head,-1,sizeof(head));cnt=0;
        int p;
        scanf("%d%d%d%d",&n,&m,&k,&p);
        for(int i=1;i<=p;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);add(v,u,w);
        }
        int q;
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            int id,u,v;
            scanf("%d%d%d",&id,&u,&v);
            for(int j=u;j<=v;j++){
                flag[j][id]=true;
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=i;j<=n;j++){
                tim[i][j]=spfa(i,j);
            }
        }
        dp();
        cout<<f[1][n]<<endl;
        return 0;
    }
    

      

  • 相关阅读:
    sklearn Pipeline 和Ploynomial
    python PCA
    python numpy 包积累
    python 画图
    Sklearn——逻辑回归
    R语言链接数据库
    R语言清空环境所有变量
    wordpress调用文件
    WordPress时间日期函数常用代码
    如何使WordPress博客添加多个sidebar侧边栏
  • 原文地址:https://www.cnblogs.com/imzscilovecode/p/8974488.html
Copyright © 2011-2022 走看看