P1772 [ZJOI2006] 物流运输

Posted on 2022-10-18 20:30  Capterlliar  阅读(21)  评论(0编辑  收藏  举报

题意:给出一张有m个结点,e条边的带权无向图,其中结点代表码头,边代表航线。试安排n天从1到m的航线,其中有特定时间一些码头不能用(即路线不能经过这个结点),如果当天航线和前一天不同,要额外花费k。求最小花费。

解:试图dp。先设dp[i][j]为第 i 天到结点 j 的最小花费。如果没有时不时关闭的码头,那直接把最短路乘n就可以了。现在有的结点不能用,那选的路线就会和前面不一样。考虑怎么记录路线。边有200条,不可能状压。考虑预处理一些东西。想要记录路线,目的是对比和前一天路线是否一样。如果有两天路线一样,那么这条路上没有两天都禁用的结点。处理每一个连续区间不换路线的最少花费,也就是删除这几天所有被禁节点后的最短路长度乘以天数,这样转移的时候只要枚举哪几天连在一起就可以了。设dp[i]为第i天为止的最小花费,dp[i]=min(dp[j]+cost[j+1][i]),n2复杂度,反正数字小,随便跑。记得开long long。

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxx 105
#define maxn 25
#define maxm 205
#define ll long long
#define inf 1000000009
#define mod 998244353
int n,m,k,ed;
struct node{
    int u,v,w;
    int nxt;
}e[maxm*2];
int head[maxn]={0};int cnt=0;
void add(int u,int v,int w){
    e[++cnt].u=u;
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}
ll dis[maxn],vis[maxn];
ll cost[maxx][maxx]={0};
ll dp[maxx]={0};
int p[maxn][maxx]={0};
ll dijk(){
    priority_queue<pair<int,int> > q;
    dis[1]=0;
    q.push(make_pair(0,1));
    while(!q.empty()){
        int now=q.top().second;
        q.pop();
        if(vis[now])
            continue;
        vis[now]=1;
        for(int i=head[now];i;i=e[i].nxt){
            int to=e[i].v;
            ll f=dis[now]+e[i].w;
            if(f<dis[to]&&!vis[to]){
                dis[to]=f;
                q.push(make_pair(-dis[to],to));
            }
        }
    }
    return dis[m];
}
signed main(){
//    int T;
//    scanf("%d",&T);
//    while(T--){
//
//    }
    scanf("%d%d%d%d",&n,&m,&k,&ed);
    for(int i=0;i<ed;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    int d;
    scanf("%d",&d);
    for(int i=0;i<d;i++){
        int num,x,y;
        scanf("%d%d%d",&num,&x,&y);
        for(int j=x;j<=y;j++)
            p[num][j]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            for(int kk=1;kk<=m;kk++)
                dis[kk]=inf,vis[kk]=0;
            for(int node=1;node<=m;node++){
                for(int day=i;day<=j;day++) {
                    if (p[node][day]){
                        vis[node]=1;
                        break;
                    }
                }
            }
            cost[i][j]=dijk()*(j-i+1);
        }
    }
    dp[0]=inf;
    for(int i=1;i<=n;i++){
        dp[i]=cost[1][i];
        for(int j=0;j<i;j++){
            dp[i]=min(dp[i],dp[j]+cost[j+1][i]+k);
        }
    }
    printf("%lld\n",dp[n]);
    return 0;
}
View Code