bzoj1003(ZJOI2006)物流运输

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

一开始撕逼地以为是撕逼题。贪心什么的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int T=105,N=25;const ll INF=0x7fffffff;
int t,n,m,K,head[N],xnt,ky[T];
ll cd[(1<<20)+5],qd,lm,dis[N],mn,ans;
bool vis[N];
struct Edge{
    int next,to;ll w;
    Edge(int n=0,int t=0,ll w=0):next(n),to(t),w(w) {}
}edge[805];
void add(int x,int y,ll z)
{
    edge[++xnt]=Edge(head[x],y,z);head[x]=xnt;
    edge[++xnt]=Edge(head[y],x,z);head[y]=xnt;
}
bool ck(int s,int i){return s&(1<<i);}
void dj(int s)
{
    memset(dis,1,sizeof dis);dis[1]=0;
    priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
    memset(vis,0,sizeof vis);q.push(make_pair(0,1));
    while(q.size())
    {
        int k=q.top().second;q.pop();
        while(vis[k]&&q.size())k=q.top().second,q.pop();
        if(vis[k])break;vis[k]=1;if(k==n)break;
        for(int i=head[k],v;i;i=edge[i].next)
            if(!vis[v=edge[i].to]&&ck(s,v)&&dis[v]>dis[k]+edge[i].w)
                dis[v]=dis[k]+edge[i].w,q.push(make_pair(dis[v],v));
    }
    cd[s]=dis[n];
}
void init()
{
    qd=((1<<1)|(1<<n));lm=(1<<(n+1));memset(cd,1,sizeof cd);
    for(int s=qd;s<lm;s++)dj(s);
}
int main()
{
    scanf("%d%d%d%d",&t,&n,&K,&m);int x,y;ll z;
    while(m--)
    {
        scanf("%d%d%lld",&x,&y,&z);
        add(x,y,z);
    }
    init();
    scanf("%d",&m);int p;
    while(m--)
    {
        scanf("%d%d%d",&p,&x,&y);
        for(int i=x;i<=y;i++)ky[i]|=(1<<p);
    }
    mn=INF;
    for(int i=1;i<=t;i++)
    {
        mn=INF;
        for(int s=qd;s<lm;s++)
            if((ky[i]&s)==0)
                mn=min(mn,(ky[i-1]&s)==0?cd[s]:cd[s]+K);
        ans+=mn;
    }
    printf("%lld",ans);
    return 0;
}
View Code

结果并不是。主要是当前走这条路线不用切换的条件不是上一次能走这条路线,而是上一次走了这条路线。

然后去看了看TJ。啊,是区间dp呀。于是枚举区间长度,如何如何。但还是不对。

又去看TJ了。发现不应该是把两个区间dp值拼起来,而是前 j 个点的dp值+后面点的最短路值。或者至少记录一下当前dp值走了哪条路线,不然可能出现多加的切换费用。

其实最后发现可能不是因为这个错了。d j 的时候那个“ck(s,v)”,其实是“! ck(s,v)”。唉,不知道怎么过样例的。中间输出竟然也没看出来,真可怕。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int T=105,N=25;const ll INF=0x7fffffff;
int t,n,m,K,head[N],xnt,ky[T];
ll dis[N],dp[T];
bool vis[N];
struct Edge{
    int next,to;ll w;
    Edge(int n=0,int t=0,ll w=0):next(n),to(t),w(w) {}
}edge[805];
void add(int x,int y,ll z)
{
    edge[++xnt]=Edge(head[x],y,z);head[x]=xnt;
    edge[++xnt]=Edge(head[y],x,z);head[y]=xnt;
}
bool ck(int s,int i){return s&(1<<i);}
ll dj(int s)
{
    memset(dis,1,sizeof dis);dis[1]=0;
    priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
    memset(vis,0,sizeof vis);q.push(make_pair(0,1));
    while(q.size())
    {
        int k=q.top().second;q.pop();
        while(vis[k]&&q.size())k=q.top().second,q.pop();
        if(vis[k])break;vis[k]=1;if(k==n)break;
        for(int i=head[k],v;i;i=edge[i].next)
            if(!vis[v=edge[i].to]&&!ck(s,v)&&dis[v]>dis[k]+edge[i].w)//
                dis[v]=dis[k]+edge[i].w,q.push(make_pair(dis[v],v));
    }
    return dis[n];
}
ll sy(int l,int r)
{
    int sm=0;for(int j=l;j<=r;j++)sm|=ky[j];
    return dj(sm)*(r-l+1);
}
int main()
{
    scanf("%d%d%d%d",&t,&n,&K,&m);int x,y;ll z;
    while(m--)
    {
        scanf("%d%d%lld",&x,&y,&z);
        add(x,y,z);
    }
    scanf("%d",&m);int p;
    while(m--)
    {
        scanf("%d%d%d",&p,&x,&y);
        for(int i=x;i<=y;i++)ky[i]|=(1<<p);
    }
    memset(dp,1,sizeof dp);dp[0]=0;
    for(int i=1;i<=t;i++)
    {
        for(int j=0;j<i;j++)
            dp[i]=min(dp[i],dp[j]+sy(j+1,i)+K);
    }
    printf("%lld",dp[t]-K);
    return 0;
}

 

posted on 2018-06-04 11:00  Narh  阅读(141)  评论(0编辑  收藏  举报

导航