洛谷 P1073 最优贸易

题目描述

C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市。任意两个

城市之间最多只有一条道路直接相连。这 m 条道路中有一部分为单向通行的道路,一部分

为双向通行的道路,双向通行的道路在统计条数时也计为 1 条。

C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价

格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。

商人阿龙来到 C 国旅游。当他得知同一种商品在不同城市的价格可能会不同这一信息

之后,便决定在旅游的同时,利用商品在不同城市中的差价赚回一点旅费。设 C 国 n 个城

市的标号从 1~ n,阿龙决定从 1 号城市出发,并最终在 n 号城市结束自己的旅行。在旅游的

过程中,任何城市可以重复经过多次,但不要求经过所有 n 个城市。阿龙通过这样的贸易方

式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品――水晶球,并在之后经过的另

一个城市卖出这个水晶球,用赚取的差价当做旅费。由于阿龙主要是来 C 国旅游,他决定

这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。

假设 C 国有 5 个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路

为单向通行,双向箭头表示这条道路为双向通行。

假设 1~n 号城市的水晶球价格分别为 4,3,5,6,1。

阿龙可以选择如下一条线路:1->2->3->5,并在 2 号城市以 3 的价格买入水晶球,在 3

号城市以 5 的价格卖出水晶球,赚取的旅费数为 2。

阿龙也可以选择如下一条线路 1->4->5->4->5,并在第 1 次到达 5 号城市时以 1 的价格

买入水晶球,在第 2 次到达 4 号城市时以 6 的价格卖出水晶球,赚取的旅费数为 5。

现在给出 n 个城市的水晶球价格,m 条道路的信息(每条道路所连接的两个城市的编号

以及该条道路的通行情况)。请你告诉阿龙,他最多能赚取多少旅费。

输入输出格式

输入格式:

第一行包含 2 个正整数 n 和 m,中间用一个空格隔开,分别表示城市的数目和道路的

数目。

第二行 n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这 n 个城

市的商品价格。

接下来 m 行,每行有 3 个正整数,x,y,z,每两个整数之间用一个空格隔开。如果 z=1,

表示这条道路是城市 x 到城市 y 之间的单向道路;如果 z=2,表示这条道路为城市 x 和城市

y 之间的双向道路。

输出格式:

输出文件 trade.out 共 1 行,包含 1 个整数,表示最多能赚取的旅费。如果没有进行贸易,

则输出 0。

输入输出样例

输入样例#1:
5 5 
4 3 5 6 1 
1 2 1 
1 4 1 
2 3 2 
3 5 1 
4 5 2 
输出样例#1:
5

说明

【数据范围】

输入数据保证 1 号城市可以到达 n 号城市。

对于 10%的数据,1≤n≤6。

对于 30%的数据,1≤n≤100。

对于 50%的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。

对于 100%的数据,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤各城市

水晶球价格≤100。

NOIP 2009 提高组 第三题0

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio> 
 4 #include<vector>
 5 #include<queue>
 6 #define maxn 100000+5
 7 using namespace std;
 8 struct Edges{
 9     int from,to,next;
10 }e[maxn*10];
11 int n,m,dis[maxn],ru[maxn],chu[maxn],head[maxn],tot;
12 bool vis[maxn];
13 inline void addedge(int u,int v){
14     /*Edges e;e.from=u;e.to=v;
15     edge.push_back(e);int m=edge.size();
16     G[u].push_back(m-1);*/
17     e[++tot].from=u;e[tot].to=v;
18     e[tot].next=head[u];head[u]=tot;
19 }
20 int spfa(int U,int V){
21     for(int i=1;i<=n;i++)dis[i]=-maxn;
22     dis[U]=0;vis[U]=1;queue<int>q;
23     q.push(U);
24     int u;
25     while(!q.empty()){
26         u=q.front();q.pop();vis[u]=0;
27         for(int i=head[u];i;i=e[i].next){
28             bool mark=0;
29             if(dis[e[i].to]<chu[e[i].to]-ru[e[i].from]){
30                 dis[e[i].to]=chu[e[i].to]-ru[e[i].from];
31                 ru[e[i].to]=min(ru[e[i].to],ru[e[i].from]);
32                 mark=1;
33             }
34             if(dis[e[i].to]<dis[e[i].from]){
35                 dis[e[i].to]=dis[e[i].from];
36                 ru[e[i].to]=min(ru[e[i].to],ru[e[i].from]);
37                 mark=1;
38             }
39             if(mark)
40               if(!vis[e[i].to]) q.push(e[i].to);
41         }
42     }
43     if(dis[V]>0)
44         return dis[V];
45     return 0;
46 }
47 int main(){
48     scanf("%d%d",&n,&m);
49     for(int i=1;i<=n;i++){
50         scanf("%d",&ru[i]);
51         chu[i]=ru[i];
52     }
53     for(int i=1,x,y,z;i<=m;i++){
54         scanf("%d%d%d",&x,&y,&z);
55         addedge(x,y);
56         if(z==2) addedge(y,x);
57     }
58     printf("%d",spfa(1,n));
59 }

莫名的RE-_- -_-

 我的思路是ru维护到当前点始最低买入价格、chu维护到当前点时最高卖出价格

来自神犇的AC代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 const int maxn = 100010;
  8 const int maxe = 500050;
  9 int n,m,tot1,tot2,dis[maxn];
 10 int fst1[maxn],fst2[maxn],minn[maxn],maxx[maxn];
 11 bool vis1[maxn],vis2[maxn];
 12 struct edge{
 13     int to,next;
 14 }es1[maxe],es2[maxe];
 15 
 16 void build1(int ff,int tt)
 17 {
 18     es1[tot1].to = tt;
 19     es1[tot1].next = fst1[ff];
 20     fst1[ff] = tot1++;
 21 }
 22 
 23 void build2(int ff,int tt)
 24 {
 25     es2[tot2].to = tt;
 26     es2[tot2].next = fst2[ff];
 27     fst2[ff] = tot2 ++;
 28 }
 29 
 30 void spfa1()
 31 {
 32     queue<int>q;
 33     q.push(1);
 34     vis1[1] = 1;
 35     minn[1] = dis[1];
 36     while(!q.empty())
 37     {
 38         int u = q.front();
 39         q.pop();
 40         for(int i = fst1[u];i;i = es1[i].next)
 41         {
 42             int v = es1[i].to;
 43             minn[v] = min(minn[u],dis[v]);
 44             if(!vis1[v])
 45             {
 46                 q.push(v);
 47                 vis1[v] = 1;
 48             }
 49         }
 50     }
 51 }
 52 void spfa2()
 53 {
 54     queue<int>q;
 55     q.push(n);
 56     vis2[n] = 1;
 57     maxx[n] = dis[n];
 58     while(!q.empty())
 59     {
 60         int u = q.front();
 61         q.pop();
 62         for(int i = fst2[u];i;i = es2[i].next)
 63         {
 64             int v = es2[i].to;
 65             maxx[v] = max(dis[v],maxx[u]);
 66             if(!vis2[v])
 67             {
 68                 q.push(v);
 69                 vis2[v] = 1;
 70             }
 71         }
 72     }
 73 }   
 74 int main()
 75 {
 76     scanf("%d%d",&n,&m);
 77     for(int i = 1;i <= n;i ++)
 78     {
 79         scanf("%d",&dis[i]);
 80         vis1[i] = 0;
 81         vis2[i] = 0;
 82         fst1[i] = 0;
 83         fst2[i] = 0;
 84         minn[i] = 2147483647;
 85         maxx[i] = 0;
 86     }
 87     for(int i = 1;i <= m;i ++)
 88     {
 89         int x,y,z;
 90         scanf("%d%d%d",&x,&y,&z);
 91         if(z == 1)
 92         {
 93             build1(x,y);
 94             build2(y,x);
 95         }
 96         else 
 97         {
 98             build1(x,y);build1(y,x);
 99             build2(x,y);build2(y,x);
100         }
101     }
102     spfa1();
103     spfa2();
104     int ans = 0;
105     for(int i = 1;i <= n;i ++)
106     ans = max(ans,maxx[i] - minn[i]);
107     printf("%d",ans);
108     return 0;
109 }

不懂为什么要建反边~~

还有来自神犇的暴力代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 #define N 100002
 7 int n,m,s[N],maxn[N],minn[N],ans;
 8 vector<int>a[N],b[N];
 9 void dfs1(int g ,int h){//g为城市编号,h为当前城市的价格 
10     minn[g]=min(h,minn[g]);//因为双向边可以来回,买价可以更低 
11     for(int i=0;i<a[g].size();i++)
12         if(h<minn[a[g][i]]) 
13             dfs1(a[g][i],min(s[a[g][i]],h));    
14 }
15 void dfs2(int g ,int h){//同理
16     maxn[g]=max(h,maxn[g]);
17     for(int i=0;i<b[g].size();i++)
18         if(h>maxn[b[g][i]]) 
19             dfs2(b[g][i],max(s[b[g][i]],h));
20 }
21 int main(){
22     scanf("%d%d",&n,&m);
23     for(int i=1;i<=n;i++)
24         scanf("%d",s+i);//每个城市的价格 
25     for(int i=1,x,y,z;i<=m;i++){
26         scanf("%d%d%d",&x,&y,&z);
27         if(z==1)
28             a[x].push_back(y),b[y].push_back(x);//单边 
29         else
30             a[x].push_back(y),a[y].push_back(x),b[x].push_back(y),b[y].push_back(x);//双边  
31     }
32     for(int i=1;i<=n;i++)
33         maxn[i]=-1e9,minn[i]=1e9;
34     dfs1(1,s[1]);//低价买
35     dfs2(n,s[n]);//高价卖 
36     for(int i=1;i<=n;i++)
37         if(maxn[i]!=-1e9&&minn[i]!=1e9)
38             ans=max(ans,maxn[i]-minn[i]);
39     printf("%d
",ans);
40     return 0;
41 }
原文地址:https://www.cnblogs.com/suishiguang/p/6413954.html