P1073 最优贸易【SPFA】

题目链接传送门


@xuxiayang

整个机房的 A C AC AC 都因他而起。

@liuzihan

他造就了我的 A C AC AC


步入正题:

这道题其实就是让你
先跑一遍 S P F A SPFA SPFA
用来求出最低买入水晶球价格
再将图反置,从后往前
再跑一遍 S P F A SPFA SPFA
用来求出最高卖出水晶球价格
最后从2到n
求出一个最大最高价值减去最小价值的值


提几个要点:

1. 领接表的建立

这次领接表的建立有点不一样
需要分两种情况分别建立

void ljb1(int x,int y)              // NO。1
{
	e1[++tot1].x=x;
	e1[tot1].to=y;
	e1[tot1].next=hd1[x];
	hd1[x]=tot1;
}
void ljb2(int x,int y)              // NO.2
{
	e2[++tot2].x=x;
	e2[tot2].to=y;
	e2[tot2].next=hd2[x];
	hd2[x]=tot2;
}

2. 反置

反置的意思:

就是把图中所有的线路全部反过来
如下图:
在这里插入图片描述
在这里插入图片描述
这与第一个要点相关联,
我们需要判断 z z z 的类型
1 1 1
就单向并反置,
2 2 2
就双向并反置。


知道了这些东西: 我们就能做出来啦!
(搞了一个晚上)

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,m,w[100100];
int dis1[1000100],dis2[1000100];
int dl1[1000100];
int v1[1010001];
int tot1,tot2,hd1[10001000],hd2[10001000];
int ans;
struct node1
{
	int x,to,next;
}e1[10000010];
struct node2
{
	int x,to,next;
}e2[1000100];
void ljb1(int x,int y)
{
	e1[++tot1].x=x;
	e1[tot1].to=y;
	e1[tot1].next=hd1[x];
	hd1[x]=tot1;
}
void ljb2(int x,int y)
{
	e2[++tot2].x=x;
	e2[tot2].to=y;
	e2[tot2].next=hd2[x];
	hd2[x]=tot2;
}
void spfa1(int x)
{
	memset(dis1,0x3f,sizeof(dis1));
	int head=0,tail=1;
	dis1[x]=w[x],v1[x]=1,dl1[1]=x;
	while(head!=tail)
	 {  
	 	head=head%100010+1;
	 	int x1=dl1[head];
	 	for(int i=hd1[x1];i;i=e1[i].next)
	 	 {
	 	 	if(min(w[e1[i].to],dis1[x1])<dis1[e1[i].to])
	 	 	 {
	 	 	 	dis1[e1[i].to]=min(w[e1[i].to],dis1[x1]);
	 	 	    if(v1[e1[i].to]==0)
	 	 	     {
	 	 	 	   tail=tail+1;
	 	 	 	   v1[e1[i].to]=1;
	 	 	 	   dl1[tail]=e1[i].to;
	 	 	     }
	 	 	 }
	 	 }
	 	v1[x1]=0;
	 }
}
void spfa2(int x)
{
	memset(v1,0,sizeof(v1));
	int head=0,tail=1;
	dis2[x]=w[x],v1[x]=1,dl1[1]=x;
	while(head!=tail)
	 {
	 	head=head%1000100+1;
	 	int x1=dl1[head];
	 	for(int i=hd2[x1];i;i=e2[i].next)
	 	 {
	 	 	if(max(w[e2[i].to],dis2[x1])>dis2[e2[i].to])
	 	 	 {
	 	 	 	dis2[e2[i].to]=max(w[e2[i].to],dis2[x1]);
	 	 	    if(v1[e2[i].to]==0)
	 	 	     {
	 	 	 	   tail=tail+1;
	 	 	 	   v1[e2[i].to]=1;
	 	 	 	   dl1[tail]=e2[i].to;
	 	 	 	 }
	 	 	 }
	 	 
	 	 }
	 	v1[x1]=0;
	 }
}
int main()
{
	cin>>n>>m;
	for(int i=1; i<=n; i++)
	   cin>>w[i];
	for(int i=1; i<=m; i++)
	 {
	 	int x,y,z;
	 	cin>>x>>y>>z;
	 	if(z==1)
	 	 {
	 	 	ljb1(x,y);
	 	 	ljb2(y,x);
	 	 }
	 	else if(z==2)
	 	 {
	 	   ljb1(x,y);
	 	   ljb1(y,x);
	 	   ljb2(y,x);
	 	   ljb2(x,y);
	     }
	 }
	spfa1(1);
	spfa2(n);
	ans=0;
    for(int i=2; i<n; i++)
       ans=max(ans,dis2[i]-dis1[i]);
    cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值