zoukankan      html  css  js  c++  java
  • noip模拟赛 虫洞

    题目描述

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

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

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

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

    作为压轴题,自然不会是如此简单的最短路问题,所以每过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。

    输出格式:

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

    输入输出样例

    输入样例#1:
    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
    输出样例#1:
    130

    说明

    对于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->3->4的路线。

    分析:本质上就是最短路问题,一个点具有两个性质,一般而言都要拆成两个具有不同性质的点,这两个点根据题目说的白变黑,黑变白来连边,然后继续连边,跑一边规模为2*n的spfa就过了。第一次做没看清题目,每次跑过虫洞都要消耗1单位时间......

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    
    using namespace std;
    
    const int maxn = 501000,maxm = 10001000,inf = 0x7ffffff;
    
    int n,m,flag[maxn],to[maxm],nextt[maxm],tot = 1,head[maxn],mg[maxn],s[maxn];
    int d[maxn],vis[maxn],w[maxn];
    
    //1 ~ n为白,n + 1 ~ 2n为黑 
    
    void add(int x,int y,int z)
    {
        to[tot] = y;
        w[tot] = z;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void spfa(int s)
    {
        queue <int> q;
        q.push(s);
        for (int i = 1; i <= 2 * n; i++)
        d[i] = inf;
        d[s] = 0;
        vis[s] = 1;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for (int i = head[u];i;i = nextt[i])
            {
                int v = to[i];
                if (d[v] > d[u] + w[i])
                {
                    d[v] = d[u] + w[i];
                    if (!vis[v])
                    {
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i = 1; i <= n; i++)
        scanf("%d",&flag[i]);
        for (int i = 1; i <= n; i++)
        scanf("%d",&mg[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 (flag[u] == flag[v])
            {
                add(u,v + n,k);
                add(u + n,v,k);
            } 
            else
            {
                add(u + n,v + n,k + abs(mg[u] - mg[v]));
                int c = max(0,k - abs(mg[u] - mg[v]));
                add(u,v,c);
            }
        }
        for (int i = 1; i <= n; i++)
        {
        add(i,i + n,0);
        add(i + n,i,s[i]);
        }
        if (flag[1])
        spfa(1 + n);
        else
        spfa(1);
        printf("%d
    ", min(d[n],d[2 * n]));
    
        return 0;
    }
  • 相关阅读:
    LeetCode Merge Two Sorted Lists 归并排序
    LeetCode Add Binary 两个二进制数相加
    LeetCode Climbing Stairs 爬楼梯
    034 Search for a Range 搜索范围
    033 Search in Rotated Sorted Array 搜索旋转排序数组
    032 Longest Valid Parentheses 最长有效括号
    031 Next Permutation 下一个排列
    030 Substring with Concatenation of All Words 与所有单词相关联的字串
    029 Divide Two Integers 两数相除
    028 Implement strStr() 实现 strStr()
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7537884.html
Copyright © 2011-2022 走看看