最优贸易

题目链接

这道题的题目大意:

它给你一些点和边,点上有权值,让你求出从1走到n(可以重走,但不可以在1和n进行贸易),途中最小的值和最大值的差(最大值在最小值走过之后)。


听了dalao的讲解,通过dalao的更改,我终于AC了
最优贸易_第1张图片


现在来分析:

这题不难想到用SPFA,但要用两次SPFA
我们不难想到O(N^4)的算法,但会超时
最优贸易_第2张图片

我们可以不考虑在哪里买入和卖出,只考虑一个定点,用SPFA分别算出从1~x在从n-x的最小点值和最大点值,最后循环求答案(有可能不进行贸易)

最大值要把图反过来


上代码:

#include
#include
#include
using namespace std;
int m,n,k,a[100100],maxx[1000100],minn[1000100],v[1010001],f[1000100],ans;
struct node{
	int x,y,next,w;
}xx[10000010];
node yy[1000100];
int tot,tot1,hd1[10001000],hd[1001000];
void add1(int x,int y,int w){
	tot++;
	xx[tot].x=x;
	xx[tot].y=y;
	xx[tot].w=w;
	xx[tot].next=hd[x];
	hd[x]=tot;
}
void add2(int x,int y,int w){
	tot1++;
	yy[tot1].x=x;
	yy[tot1].y=y;
	yy[tot1].w=w;
	yy[tot1].next=hd1[x];
	hd1[x]=tot1;
}
void spfa(int x){
	memset(minn,0x3f,sizeof(minn));
	minn[x]=a[x];
	v[x]=1;
	f[1]=x;
	int head=0,tail=1;
	while(head!=tail){
		head=head%100010+1; 
		int x1=f[head];
		for(int i=hd[x1];i;i=xx[i].next){
			if(minn[xx[i].y]>min(a[xx[i].y],minn[x1])){
				minn[xx[i].y]=min(a[xx[i].y],minn[x1]);
				if(v[xx[i].y]==0){
					tail++;
					v[xx[i].y]=1;
					f[tail]=xx[i].y;
				}
			}
		}
		v[x1]=0;
	}
}
void spfa1(int x){
	memset(v,0,sizeof(v));
	maxx[x]=a[x];
	v[x]=1;
	f[1]=x;
	int head=0,tail=1;
	while(head!=tail){
		head=head%100010+1; 
		int x1=f[head];
		for(int i=hd1[x1];i;i=yy[i].next){
			if(maxx[yy[i].y]<max(a[yy[i].y],maxx[x1])){
				maxx[yy[i].y]=max(a[yy[i].y],maxx[x1]);
				if(v[yy[i].y]==0){
					 tail++;
					v[yy[i].y]=1;
				  	f[tail]=yy[i].y;
				}  
			}
		}  
		v[x1]=0;
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=m;i++){
		int x,y,k;
		cin>>x>>y>>k;
		if(k==1){
			add1(x,y,a[y]);
			add2(y,x,a[x]);
		}
		else{
			add1(x,y,a[y]);
			add1(y,x,a[x]);
			add2(x,y,a[y]);
			add2(y,x,a[x]);
		}//邻接表
	}
	spfa(1);//最大值
	spfa1(n);//最小值
	ans=0;
	for(int i=2;i<n;i++){
		ans=max(ans,maxx[i]-minn[i]);
	}//定点x枚举
	cout<<ans;
}

你可能感兴趣的:(题解,SPFA,最短路)