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\n", min(d[n],d[2 * n]));

    return 0;
}

 

posted @ 2017-09-17 21:25  zbtrs  阅读(456)  评论(0编辑  收藏  举报