专栏文章

题解:P1073 [NOIP2009 提高组] 最优贸易

P1073题解参与者 7已保存评论 8

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
8 条
当前快照
1 份
快照标识符
@miqi3sl8
此快照首次捕获于
2025/12/04 05:10
3 个月前
此快照最后确认于
2025/12/04 05:10
3 个月前
查看原文
upd 2025/1/172025/1/17:修改错别字

题意概括

给你一个长度为 nn 的序列 ana_n,代表权值。
从节点 11 到节点 nn 有若干条路径,路径上任意取两个点 xxyy,满足:
  • xxyy 先访问。
  • ayaxa_y-a_x 尽可能地大。
求最大的 ayaxa_y-a_x

思路

考虑分层图。
什么是分层图?
分层图是一种在图论中用于解决特定问题的建模方法。它通过将原始图复制成多层结构,每一层代表不同的状态或决策次数,从而在这些层之间建立特定的连接,以满足问题的约束条件。 —ChatGPT
就以这个题举例。
我们需要进行买入卖出两次操作,当买了在第 ii 个城市买了水晶球时,代价是 ai-a_i,卖出的代价是 aia_i,不买不卖就是 00
我们可以建三层图,第一层代表没买也没卖,第二层代表买了但没卖,第三层代表买了也卖了。
如图:
graph 5-topaz-upscale-4x.png
在这个图上跑最长路就好了。

关于建图:

对于第 ii 个点,对 iii+ni+n 连一条边权为 ai-a_i 的边,i+ni+ni+2×ni+2 \times n 连一条边权为 aia_i 的边。(11)
对于每一对 u,vu,vuuvv 连一条边权 00 的边,u+nu+nv+nv+n 连一条边权 00 的边,u+2×nu+2\times nv+2×nv+2\times n 连一条边权 00 的边。(22)
(上面的图都能体现)。
参考代码:
C
for(int i=1;i<=n;i++){
	cin>>w[i];
	g[i].push_back({i+n,-w[i]});
	g[i+n].push_back({i+2*n,w[i]});
}//第一种情况
g[u].push_back({v,0});
g[u+n].push_back({v+n,0});
g[u+2*n].push_back({v+2*n,0});
//第二种情况
时间复杂度:O(3nm)O(3nm)

Code

C
#include<bits/stdc++.h>
#define int long long
#define bug cout<<"___songge888___"<<'\n';
using namespace std;
int n,m;
struct lyl{
	int v,w;
};
vector<lyl> g[500010];
int w[500010],vis[500010],dis[500010];
queue<int> q;
void spfa(int s){
	q.push(s);
	dis[s]=0;
	vis[s]=1;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(auto [v,w]:g[u]){
			if(dis[v]<dis[u]+w){
				dis[v]=dis[u]+w;
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return ;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>w[i];
		g[i].push_back({i+n,-w[i]});
		g[i+n].push_back({i+2*n,w[i]});
	}
	for(int i=1;i<=m;i++){
		int u,v,op;
		cin>>u>>v>>op;
		if(op==1){
			g[u].push_back({v,0});
			g[u+n].push_back({v+n,0});
			g[u+2*n].push_back({v+2*n,0});
		}
		else{
			g[u].push_back({v,0});
			g[u+n].push_back({v+n,0});
			g[u+2*n].push_back({v+2*n,0});
			g[v].push_back({u,0});
			g[v+n].push_back({u+n,0});
			g[v+2*n].push_back({u+2*n,0});
		}
	}
	memset(dis,128,sizeof dis);
	spfa(1);
	cout<<max(dis[n],dis[3*n]);
	return 0;
}

评论

8 条评论,欢迎与作者交流。

正在加载评论...