【luogu 1073】最优贸易【spfa】

Time Limit:10000MS Memory Limit:65536K
Total Submit:28 Accepted:25
Case Time Limit:1000MS


Description
在这里插入图片描述


Input
在这里插入图片描述


Output
在这里插入图片描述


解题思路

这一道题想了挺久的 然鹅还是没有想出正解 。
其实就是分为了两个spfa:
1先只算出从1出发一直到n的进价(最小值)。
2再把道路的走向全部反过来,算出从n出发一直到1的卖价(最大值)。

最后再枚举1~n算出最大的得益。


#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<cstdio>
using namespace std;
const int INF=10000000;
int n,m,k,h=0,t=1,v[100000],dis[100000][3],q[100000],head[100000],head2[100000],minn=INF,maxn,ans=0,bsy[100000];//dis[i][1]记录第一次spfa的最短路
struct c{
	int x,next; 
}a[1000000];
struct c1{
	int x,next; 
}b[1000000];
void spfa(){//第一个spfa求最小值
	memset(v,0,sizeof(v));
	for(int i=1;i<=n;i++)
	    dis[i][1]=0x7fffffff;
	dis[1][1]=bsy[1];
	v[1]=1;
	q[1]=1;
	while(h<t)
	{
		h++;
		for(int i=head[q[h]];i;i=a[i].next)
		{
			if(min(bsy[a[i].x],dis[q[h]][1])<dis[a[i].x][1])
			{
				dis[a[i].x][1]=min(bsy[a[i].x],dis[q[h]][1]);
				if(!v[a[i].x])
				{
					t++;
					v[a[i].x]=1;
					q[t]=a[i].x;
				}
			}
		}
		v[q[h]]=0;
	}
}
void spfa2(){//第二个spfa求最大值
	memset(v,0,sizeof(v));
	memset(q,0,sizeof(q));
	dis[1][2]=bsy[n];
	v[n]=1;
	q[1]=n;
	h=0,t=1;
	while(h<t)
	{
		h++;
		for(int i=head2[q[h]];i;i=b[i].next)
		{
			if(max(bsy[b[i].x],dis[q[h]][2])>dis[b[i].x][2])
			{
				dis[b[i].x][2]=max(bsy[b[i].x],dis[q[h]][2]);
				if(!v[b[i].x])
				{
					t++;
					v[b[i].x]=1;
					q[t]=b[i].x;
				}
			}
		}
		v[q[h]]=0;
	}
}
void add(int x,int y){ //顺行的邻接表
	++k;
	a[k].x=y;
	a[k].next=head[x];
	head[x]=k;
}
void add2(int x,int y){ //逆行的邻接表
	++k;
	b[k].x=y;
	b[k].next=head2[x];
	head2[x]=k;
}
int main(){
	scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&bsy[i]);
    for(int i=1;i<=m;i++)
    {
    	int x,y,z;
    	scanf("%d%d%d",&x,&y,&z);
    	add(x,y);
    	add2(y,x);
    	if(z==2)//双向的话要再反过来执行一次
    	{
		  add(y,x);
    	  add2(x,y);
    	}
    }
    spfa();
    spfa2();
    for(int i=2;i<n;i++)
    if((dis[i][2]-dis[i][1])>ans)
    ans=dis[i][2]-dis[i][1];
    cout<<ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值