zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    VS 2012 + NDK + ADT 开发(Cocos2d-x 3.1开发)PART 2
    VS 2012 + NDK + ADT 开发(Cocos2d-x 3.1开发)PART 1
    WebView读取SD卡上的HTML
    安卓隐藏控件
    OMNET++安装
    产品质量的核心——概念的完整性
    关于异常
    基类与子类之间的引用转换
    成绩划分 处理异常
    《大道至简 第七、八章》读后感
  • 原文地址:https://www.cnblogs.com/Narh/p/9132270.html
Copyright © 2011-2022 走看看