zoukankan      html  css  js  c++  java
  • 最短路(建图)

                                                                              虫洞

    题目描述

    N个虫洞,M条单向跃迁路径。从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间。虫洞有白洞和黑洞之分。设一条跃迁路径两端的虫洞质量差为delta。

    从白洞跃迁到黑洞,消耗的燃料值减少delta,若该条路径消耗的燃料值变为负数的话,取为0。

    从黑洞跃迁到白洞,消耗的燃料值增加delta。

    路径两端均为黑洞或白洞,消耗的燃料值不变化。

    作为压轴题,自然不会是如此简单的最短路问题,所以每过1单位时间黑洞变为白洞,白洞变为黑洞。在飞行过程中,可以选择在一个虫洞停留1个单位时间,如果当前为白洞,则不消耗燃料,否则消耗s[i] 的燃料。现在请你求出从虫洞1到N最少的燃料消耗,保证一定存在1到N的路线。

    输入格式

    第1行:2个正整数N, M

    第2行:N个整数,第i个为0表示虫洞i开始时为白洞,1 表示黑洞。

    第3行:N个整数,第i个数表示虫洞i的质量w[i]。

    第4行:N个整数,第i个数表示在虫洞i停留消耗的燃料s[i]。

    第5..M+4行:每行3个整数,u,v,k,表示在没有影响的情况下,从虫洞u到虫洞v需要消耗燃料k。

    输出格式

    一个整数,表示最少的燃料消耗。

    样例

    样例输入

    4 5
    1 0 1 0
    10 10 100 10
    5 20 15 10
    1 2 30
    2 3 40
    1 3 20
    1 4 200
    3 4 200
    

    样例输出

    130
    

    样例解释

    按照1->3->4的路线。

    数据范围与提示

    对于30%的数据: 1<=N<=100,1<=M<=500

    对于60%的数据: 1<=N<=1000,1<=M<=5000

    对于100%的数据: 1<=N<=5000,1<=M<=30000

    其中20%的数据为1<=N<=3000的链

    1<=u,v<=N, 1<=k,w[i],s[i]<=200

    思路:分层图,将白洞作为一层(结点1-n),黑洞作为一层(节点n+1-2*n)

    第一种:u与v颜色相同,因为走一条边花费一个单位时间,所以从u走到v时v以变色,Insert(u(u为白点),v+n(v为黑点),k(边权))(若开始u为白v为白)反之同上

    第二种:u与v颜色不同,因为点会按时换颜色所以即使u开始为黑v开始为白一定得建一条u到v(u到v后v变成白点)的边,但u可变成黑,同时v变白,再建一条u+n到v的边,反之,同上

    第三种:每一点可在原地停留,所以建u到u+n和u+n到u的边

    之后跑最短路,注意起始位置与1的颜色有关,最后注意比较两种情况

    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=10000+10,maxm=30000+10,inf=0x3f3f3f3f;
    int color[maxn],w[maxn],s[maxn];
    struct Edge{
        int to,next,w;
    }e[maxm<<2];
    struct Node{
        int num,w;
        Node(){};
        Node(int x,int y){
            num=x;
            w=y;
        }
        bool operator <(const Node &a)const{
             return w>a.w;
        }
    };
    int head[maxm<<2],tot=0;
    void Insert(int a,int b,int c){
         e[++tot].to=b;
         e[tot].w=c;
         e[tot].next=head[a];
         head[a]=tot;
    }
    priority_queue<Node> q;
    int d[maxn];
    void Dij(int x){
         bool vis[maxn];
         memset(vis,0,sizeof(vis));
         memset(d,0x3f,sizeof(d));
         d[x]=0;
         q.push(Node(x,0));
         while(!q.empty()){
             Node t=q.top();
             int u=t.num;
             q.pop();
             if(vis[u]) continue;
             vis[u]=1;
             for(int i=head[u];i;i=e[i].next){
                 int v=e[i].to;
                 if(d[v]>d[u]+e[i].w){
                     d[v]=d[u]+e[i].w;
                     q.push(Node(v,d[v]));
                 }
             }
         }
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&color[i]);
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        for(int i=1;i<=n;i++) scanf("%d",&s[i]);
        for(int i=1;i<=m;i++){
            int u,v,k;
            scanf("%d%d%d",&u,&v,&k);
            if(color[u]==color[v]){
                 Insert(u,v+n,k);
                 Insert(u+n,v,k);//当u与v颜色相同时,都得见两条边
            }     
            else{
                  Insert(u,v,max(0,k-abs(w[u]-w[v])));
                  Insert(u+n,v+n,k+abs(w[u]-w[v]));//u与v颜色不同
            }
        }
        for(int i=1;i<=n;i++){
            Insert(i,i+n,0);
            Insert(i+n,i,s[i]);   //在此处停留
        }
        if(color[1]==0) Dij(1);
        else Dij(1+n);//注意起始位置
        printf("%d
    ",min(d[n],d[2*n]));//最后要比较两种可能结果
        return 0;
    }
    View Code
  • 相关阅读:
    BFS visit tree
    Kth Largest Element in an Array 解答
    Merge k Sorted Lists 解答
    Median of Two Sorted Arrays 解答
    Maximal Square 解答
    Best Time to Buy and Sell Stock III 解答
    Best Time to Buy and Sell Stock II 解答
    Best Time to Buy and Sell Stock 解答
    Triangle 解答
    Unique Binary Search Trees II 解答
  • 原文地址:https://www.cnblogs.com/HZOIDJ123/p/13263260.html
Copyright © 2011-2022 走看看