「NOIP2009」最优贸易 题解 (最短路SPFA)

题目简介

咕咕咕。

分析

这道题有多种方法可以实现,我选用的是相对简单的两遍\(SPFA\)

看到网上的题解大多都是两个邻接表数组,两个存边函数,两个计算函数,我有些沾沾自喜。

将图封装在结构体中,就是香呀~

使用图 \(a\) 存从 \(1\)\(i\) 的最小进口价格,图 \(b\) 存从 \(i\)\(n\) 的最大出口价格,再遍历一遍 i ,最终答案就是

\[max\{b.D(i)-a.D(i)\} \]

带你设计结构体 \(Edge\)

struct Edge{
        ....
}a,b;

结构体 \(Edge\)

1.链式前向星(邻接表)存边

struct edge_node{
	int nxt,to;
}e[Maxn];
int head[maxn];
int tot;
inline void add(int u,int v){
	e[++tot].nxt=head[u];
	e[tot].to=v;
	head[u]=tot;
}
int x,y,z;
for(int i=1;i<=m;i++){
	x=read();y=read();z=read();
	a.add(x,y),
	b.add(y,x);
	if(!(z&1))
		a.add(y,x),
		b.add(x,y);
}

2.\(SPFA\)

这里开始值得注意了。

main() 函数中,我们的调用方法是:

a.spfa(1,1);
b.spfa(n,0);

所以此函数的定义方法是:

void spfa(int s,bool cmp)

\(cmp\) 表示的是求解 \(D\) 的方法,\(false\)表示求最小值,\(true\)表示求最大值。
自然地,\(s\) 表示的是起点位置。

\(SPFA\) 的转移条件本来是:

\[D[y]=max/min\{D[x]+dis[y]\} \]

这里应题目需要改成:

\[D[y]=max/min\{max/min\{D[x],price[y]\}\} \]

inline void spfa(int s,bool cmp){
	if(cmp)memset(d,0x3f,sizeof(d));
	queue<int>q;
	d[s]=price[s];
	v[s]=true;
	q.push(s);
	while(!q.empty()){
		int x=q.front();
		q.pop();
		v[x]=false;
		for(int i=head[x];i;i=e[i].nxt){
			int y=e[i].to;
			int z;
			if(cmp)z=mymin(d[x],price[y]);
			else z=mymax(d[x],price[y]);
			if((d[y]>z&&cmp)||(d[y]<z&&(!cmp))){
				d[y]=z;
				if(!v[y])
					q.push(y),
					v[y]=true;
			}
		}
	}
}

\(AC\) 代码

如果你久久过不了本题,请看完整代码吧:

\(SPFA\):

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int Maxn=maxn<<1;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
inline int mymax(int a,int b){return a>b?a:b;}
inline int mymin(int a,int b){return a<b?a:b;}
int price[maxn];
struct Edge{
	struct edge_node{
		int nxt,to;
	}e[Maxn];
	int head[maxn];
	int tot;
	inline void add(int u,int v){
		e[++tot].nxt=head[u];
		e[tot].to=v;
		head[u]=tot;
	}
	int d[maxn];
	bool v[maxn];
	inline void spfa(int s,bool cmp){
		if(cmp)memset(d,0x3f,sizeof(d));
		queue<int>q;
		d[s]=price[s];
		v[s]=true;
		q.push(s);
		while(!q.empty()){
			int x=q.front();
			q.pop();
			v[x]=false;
			for(int i=head[x];i;i=e[i].nxt){
				int y=e[i].to;
				int z;
				if(cmp)z=mymin(d[x],price[y]);
				else z=mymax(d[x],price[y]);
				if((d[y]>z&&cmp)||(d[y]<z&&(!cmp))){
					d[y]=z;
					if(!v[y])
						q.push(y),
						v[y]=true;
				}
			}
		}
	}
}a,b;
int n,m;
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)price[i]=read();
	int x,y,z;
	for(int i=1;i<=m;i++){
		x=read();y=read();z=read();
		a.add(x,y),
		b.add(y,x);
		if(!(z&1))
			a.add(y,x),
			b.add(x,y);
	}
	a.spfa(1,1);
	b.spfa(n,0);
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=mymax(ans,b.d[i]-a.d[i]);
	}
	printf("%d\n",ans);
	return 0;
}

由于没有负权环,可以考虑使用更稳定的堆优化,虽然对于本题没有裸 \(SPFA\)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int Maxn=maxn<<1;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
inline int mymax(int a,int b){return a>b?a:b;}
inline int mymin(int a,int b){return a<b?a:b;}
int price[maxn];
struct Edge{
	struct edge_node{
		int nxt,to;
	}e[Maxn];
	int head[maxn];
	int tot;
	inline void add(int u,int v){
		e[++tot].nxt=head[u];
		e[tot].to=v;
		head[u]=tot;
	}
	int d[maxn];
	bool v[maxn];
	inline void spfa(int s,bool cmp){
		if(cmp)memset(d,0x3f,sizeof(d));
		priority_queue<pair<int,int> >q;
		d[s]=price[s];
		v[s]=true;
		q.push(make_pair(-d[s],s));
		while(!q.empty()){
			int x=q.top().second;
			q.pop();
			v[x]=false;
			for(int i=head[x];i;i=e[i].nxt){
				int y=e[i].to;
				int z;
				if(cmp)z=mymin(d[x],price[y]);
				else z=mymax(d[x],price[y]);
				if((d[y]>z&&cmp)||(d[y]<z&&(!cmp))){
					d[y]=z;
					if(!v[y])
						q.push(make_pair(-d[y],y)),
						v[y]=true;
				}
			}
		}
	}
}a,b;
int n,m;
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)price[i]=read();
	int x,y,z;
	for(int i=1;i<=m;i++){
		x=read();y=read();z=read();
		a.add(x,y),
		b.add(y,x);
		if(!(z&1))
			a.add(y,x),
			b.add(x,y);
	}
	a.spfa(1,1);
	b.spfa(n,0);
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=mymax(ans,b.d[i]-a.d[i]);
	}
	printf("%d\n",ans);
	return 0;
}

本题较为良心,不卡 \(SPFA\) ,出于谨慎,可以加一个 \(SLF\) 优化:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int Maxn=maxn<<1;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
inline int mymax(int a,int b){return a>b?a:b;}
inline int mymin(int a,int b){return a<b?a:b;}
int price[maxn];
struct Edge{
	struct edge_node{
		int nxt,to;
	}e[Maxn];
	int head[maxn];
	int tot;
	inline void add(int u,int v){
		e[++tot].nxt=head[u];
		e[tot].to=v;
		head[u]=tot;
	}
	int d[maxn];
	bool v[maxn];
	inline void spfa_slf(int s,bool cmp){
		if(cmp)memset(d,0x3f,sizeof(d));
		deque<int>q;
		d[s]=price[s];
		v[s]=true;
		q.push_back(s);
		while(!q.empty()){
			int x=q.front();
			q.pop_front();
			v[x]=false;
			for(int i=head[x];i;i=e[i].nxt){
				int y=e[i].to;
				int z;
				if(cmp)z=mymin(d[x],price[y]);
				else z=mymax(d[x],price[y]);
				if((d[y]>z&&cmp)||(d[y]<z&&(!cmp))){
					d[y]=z;
					if(!v[y]){
						v[y]=true;
						if(q.empty()||d[y]>d[q.front()])
							q.push_back(y);
						else q.push_front(y);	
					}
				}
			}
		}
	}
}a,b;
int n,m;
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)price[i]=read();
	int x,y,z;
	for(int i=1;i<=m;i++){
		x=read();y=read();z=read();
		a.add(x,y),
		b.add(y,x);
		if(!(z&1))
			a.add(y,x),
			b.add(x,y);
	}
	a.spfa_slf(1,1);
	b.spfa_slf(n,0);
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=mymax(ans,b.d[i]-a.d[i]);
	}
	printf("%d\n",ans);
	return 0;
}

$$-----END-----$$

posted @ 2021-11-08 19:58  AlienCollapsar  阅读(57)  评论(0)    收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq