bzoj1003物流运输——DP

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1003

DP好题;

直接找一个时间段的最短路,并用它来预处理出每个时间段的最小花费;

f[i]代表一条路走到时间的花费,所以转移要加上K。

枚举所有路线的TLE代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,K,e,head[25],ct,D,d[105],rt[405],pr[405],f[105][405],cnt,ans;
bool vis[25];
struct N{
    int to,next,w;
    N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
}edge[805];
void dfs(int x,int r,int p)
{
    if(x==m)
    {
        rt[++cnt]=(r|(1<<(m-1)));
        pr[cnt]=p;
        return;
    }
    vis[x]=1;
    for(int i=head[x];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(vis[v])continue;
        dfs(v,(r|(1<<(v-1))),p+edge[i].w);
    }
    vis[x]=0;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&K,&e);
    for(int i=1,x,y,z;i<=e;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        edge[++ct]=N(y,head[x],z);head[x]=ct;
        edge[++ct]=N(x,head[y],z);head[y]=ct;
    }
    scanf("%d",&D);
    for(int i=1,p,a,b;i<=D;i++)
    {
        scanf("%d%d%d",&p,&a,&b);
        for(int j=a;j<=b;j++)d[j]|=(1<<(p-1));//第j天不能通过的码头
    }
    dfs(1,1,0);
    memset(f,0x3f,sizeof f);
    for(int j=1;j<=cnt;j++)f[0][j]=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=cnt;j++)
        {
            if(rt[j]&d[i])continue;
            for(int k=1;k<=cnt;k++)
                f[i][j]=min(f[i][j],f[i-1][k]+(j==k?pr[j]:K+pr[j]));
        }
    ans=0x3f;
    for(int j=1;j<=cnt;j++)ans=min(ans,f[n][j]);
    printf("%d",ans);
    return 0;
}

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
queue<int>q;
int const inf=0x3f3f3f3f;
int n,m,K,e,head[25],ct,mr[105][105],D,zt[25],dis[25],f[105];
bool vis[25],d[25][105];
struct N{
    int to,next,w;
    N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
}edge[805];
void spfa()
{
    memset(vis,0,sizeof vis);
    memset(dis,0x3f,sizeof dis);
    while(q.size())q.pop();
    dis[1]=0;q.push(1);vis[1]=1;
    while(q.size())
    {
        int x=q.front();q.pop();vis[x]=0;
        for(int i=head[x];i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(dis[v]>dis[x]+edge[i].w&&!zt[v])
            {
                dis[v]=dis[x]+edge[i].w;
                if(!vis[v])vis[v]=1,q.push(v);
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&K,&e);
    for(int i=1,x,y,z;i<=e;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        edge[++ct]=N(y,head[x],z);head[x]=ct;
        edge[++ct]=N(x,head[y],z);head[y]=ct;
    }
    scanf("%d",&D);
    for(int i=1,p,a,b;i<=D;i++)
    {
        scanf("%d%d%d",&p,&a,&b);
        for(int j=a;j<=b;j++)d[p][j]=1;
    }
    for(int i=1;i<=n;i++)
    {
        memset(zt,0,sizeof zt);
        for(int j=i;j<=n;j++)
        {
            for(int k=1;k<=m;k++)zt[k]|=d[k][j];
            spfa();
            mr[i][j]=dis[m];//在下面乘 小心爆int 
        }
    }
    for (int i=1;i<=n;i++)
        for (int j=i;j<=n;j++)
            if (mr[i][j]<inf)mr[i][j]*=(j-i+1);
    for(int i=1;i<=n;i++)f[i]=mr[1][i];
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<i;j++)
            f[i]=min(f[i],f[j]+mr[j+1][i]+K);
    }
    printf("%d",f[n]);
    return 0;
} 

 

posted @ 2018-06-04 11:15  Zinn  阅读(130)  评论(0编辑  收藏  举报