必威体育Betway必威体育官网
当前位置:首页 > IT技术

【分层图最短路】 2920 -- 【模拟试题】伊吹萃香

时间:2019-08-17 16:13:16来源:IT技术作者:seo实验室小编阅读:75次「手机版」
 

伊吹萃香

2920 – 【模拟试题】伊吹萃香

Description

在幻想乡,伊吹萃香是能够控制物体密度的鬼王。因为能够控制密度,所以萃香能够制造白洞和黑洞,并可以随时 改变它们。某一天萃香闲着无聊,在妖怪之山上设置了一些白洞或黑洞,由于引力的影响,给妖怪们带来了很大的麻烦。于是他们决定找出一条消耗体力最少的

路,来方便进出。已知妖怪之山上有 N个路口(编号 1…N),每个路口都被萃香设置了一定质量白洞或者黑洞。原本在各个路口之间有 M 条单向路,走过每一条路需要消耗一定量的体力以及 1 个单位的时间。由于白洞和黑洞的存在,走过每条路需要消耗的体力也就产生了变化,假设一条道路两端路口黑白洞的质量差为delta:

  1. 从有白洞的路口走向有黑洞的路口,消耗的体力值减少 delta,若该条路径消耗的体力值变为负数的话,取为0。
  2. 从有黑洞的路口走向有白洞的路口,消耗的体力值增加 delta。
  3. 如果路口两端均为白洞或黑洞,消耗的体力值无变化。

    由于光是放置黑洞白洞不足以体现萃香的强大,所以她决定每过 1 个单位时间,就把所有路口的白洞改成黑洞,黑洞改成白洞。当然在走的过程中你可以选择在一个路口上停留 1 个单位的时间,如果当前路口为白洞,则不消耗体力,否则消耗 s[i]的体力。现在请你计算从路口1 走到路口N 最小的体力消耗。保证一定存在道路从路口 1到路口N。

    Input

    第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的体力。

    Output

    第1行:1个整数,表示消耗的最小体力

    Sample Input

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

Sample Output

130

Hint

样例说明:按照1 -> 3 -> 4的路线。

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

对于60%的数据:1 <= N <= 1,000, 1 <= M <= 5,000

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

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

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

Source

幻想乡

本题实际上是简化的 分层图最短路

可将原图中的点集拆为颜色相反的两部分,分别代表奇时刻和偶时刻,不同时刻之间再相互连边,最后使用最短路算法解决即可。

时间复杂度:O(N^2)/O(NlogN)/O(KM);期望得分:100

每个点i,2i表示第i个洞的白色形态(可以这么理解吧),2i-1表示第i个洞的黑色形态

#include<iOStream>
#include<queue>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=10005,maxm=30005,INF=0x7fffffff/2;
struct Edge{int to,next,val;}a[maxm*4];
int n,m,h[maxm],cnt=0,vst[maxn],d[maxn],hole[maxn],w[maxn],tl[maxn];
queue<int>q;
void AddEdge(int x,int y,int z)
{
	a[++cnt].to=y;a[cnt].next=h[x];a[cnt].val=z;h[x]=cnt;
}
void SPFA(int v0)//最短路STL队列 
{
    int i;
    for(i=1;i<=2*n;i++)d[i]=INF;d[v0]=0;q.push(v0);vst[v0]=1;
    while(!q.empty())
    {
    	int x=q.front();q.pop();vst[x]=0;
    	for(i=h[x];i;i=a[i].next)
    	{
    		int y=a[i].to;
    		if(d[y]>d[x]+a[i].val)
    		{
    			d[y]=d[x]+a[i].val;
    			if(!vst[y]){q.push(y);vst[y]=1;}
    		}
    	}
    }
}
int main()
{
	int j,i,x,y,z;
	cin>>n>>m;
	for(i=1;i<=n;i++)cin>>hole[i];//hole表示起初这个洞是black还是white 
	for(i=1;i<=n;i++)cin>>w[i];//质量 
	for(i=1;i<=n;i++)cin>>tl[i];//原地螺旋(划掉)走需要的体力 
	for(i=1;i<=m;i++)
	{
		cin>>x>>y>>z;
		if(hole[x]==hole[y])//x,y都为同颜色 
		{
		AddEdge(2*x,2*y-1,z);//x白到y黑 
		AddEdge(2*x-1,2*y,z);}//x黑到y白 
		else 
		{
			int delta=abs(w[x]-w[y]);
			AddEdge(2*x-1,2*y-1,z+delta);//x白到y白 
		AddEdge(2*x,2*y,max(0,z-delta));//x黑到y黑 
		}
	}
		for(i=1;i<=n;i++)//2*i表示白,2*i-1表示黑 
	{
		AddEdge(i*2-1,i*2,tl[i]);//i黑到i白,自我螺旋到黑,消耗体力 
		AddEdge(i*2,i*2-1,0);//i白到i黑 ,不用花费体力 
	}
	SPFA(2-hole[1]);//注意不是从0开始 
	cout<<min(d[2*n],d[n*2-1]);
	return 0;
}

相关阅读

分享到:

栏目导航

推荐阅读

热门阅读