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;
}

  

posted @ 2018-04-30 20:05  愿~得偿所愿,不负时光  阅读(297)  评论(0编辑  收藏  举报