• 最短路(建图)


                                                                              虫洞

    题目描述

    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
  • 相关阅读:
    bootstrapValidator重新校验/全选回显
    mybatis遍历map参数查询
    location.href传json字符串
    springmvc异步处理
    intellIJ IDEA学习笔记3
    intellIJ IDEA学习笔记2
    intellIJ IDEA学习笔记
    maven国内镜像
    Docker版本Jenkins的使用
    Docker容器网络
  • 原文地址:https://www.cnblogs.com/HZOIDJ123/p/13263260.html
Copyright © 2020-2023  润新知