P1073 最优贸易

最优贸易

洛谷链接

这道题是09年提高组的第三题。

题目大意:

有个商人在一个图上走,图上的点有权值,各个点之间有边相连,求出在商人可以到达终点的条件下,所经历的点的最小权值与最大权值的差(每个点或边可以走多次)。

这个题有两种做法:

1.

用两遍dfs,一遍求出点的min,另一边求出点的max,最后两个数组相减,找出最大值,得出答案。

代码:

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 int n,m;
 7 int num_edge1,num_edge2;
 8 int ans;
 9 int a[100001];
10 int    maxx[100001],minn[100001],head1[100001],head2[100001];
11 int x,y,z;
12 struct hehe{
13     int next;
14     int to;
15 };
16 hehe edge1[1000001],edge2[1000001];
17 inline void add_edge1(int from,int to){
18     edge1[++num_edge1].next=head1[from];
19     edge1[num_edge1].to=to;
20     head1[from]=num_edge1;
21 }
22 inline void add_edge2(int from,int to){
23     edge2[++num_edge2].next=head2[from];
24     edge2[num_edge2].to=to;
25     head2[from]=num_edge2;
26 }
27 inline void dfs2(int u,int k){
28     int i,v;
29     maxx[u]=max(maxx[u],k);
30     for(i=head2[u];i!=-1;i=edge2[i].next){
31         v=edge2[i].to;
32         if(maxx[v]<k)dfs2(v,max(k,a[v]));
33     }
34 }
35 inline void dfs1(int u,int k){
36     int v;
37     minn[u]=min(minn[u],k);
38     for(int i=head1[u];i!=-1;i=edge1[i].next){ 
39         v=edge1[i].to;
40         if(minn[v]>k)
41             dfs1(v,min(k,a[v]));
42     }
43 }
44 int main(){
45     memset(head1,-1,sizeof(head1));
46     memset(head2,-1,sizeof(head2));
47     scanf("%d%d",&n,&m);
48     for(int i=1;i<=n;i++){
49         scanf("%d",&a[i]);
50         maxx[i]=-4200000; 
51         minn[i]=4200000;
52     }
53     for(int i=1;i<=m;i++){
54         scanf("%d%d%d",&x,&y,&z);
55         if(z==2){ 
56             add_edge1(x,y); 
57             add_edge1(y,x);
58             add_edge2(x,y);
59             add_edge2(y,x);
60         }
61         else{
62             add_edge1(x,y);
63             add_edge2(y,x);
64         }
65     }
66     dfs1(1,a[1]);
67     dfs2(n,a[n]);
68     for(int i=1;i<=n;i++)
69         ans=max(ans,maxx[i]-minn[i]);
70     printf("%d",ans);
71     return 0;
72 }
View Code

2.

先用dfs求出可以到达根节点的节点,之后一遍spfa,求出到该节点时,可以走到的最小的权值是多少,最后找出最大值,得到答案。

代码:

 1 #include<queue>
 2 #include<cstdio>
 3 #define N 100010
 4 #define M 1000010
 5 using namespace std;
 6 queue<int>p;
 7 int next1[M],to1[M],num1,head1[N];
 8 int next2[M],to2[M],num2,head2[N];
 9 int a,b,c,d[N],dis[N],n,m,u,ans=-1;
10 bool boo[N],exist[N];
11 void add1(int false_from,int false_to){
12     next1[++num1]=head1[false_from];
13     to1[num1]=false_to;
14     head1[false_from]=num1;
15 }
16 void add2(int false_from,int false_to){
17     next2[++num2]=head2[false_from];
18     to2[num2]=false_to;
19     head2[false_from]=num2;
20 }
21 void dfs(int x){
22     boo[x]=1;
23     for(int i=head2[x];i;i=next2[i]){
24         if(!boo[to2[i]])
25             dfs(to2[i]);
26     }
27 }
28 void spfa(){
29     for(int i=1;i<=n;++i)
30         dis[i]=42000000;
31     p.push(1);
32     exist[1]=1;
33     while(!p.empty()){
34         u=p.front();
35         p.pop();
36         exist[u]=0;
37         for(int i=head1[u];i;i=next1[i])
38             if(dis[to1[i]]>min(dis[u],d[to1[i]])&&boo[to1[i]]){
39                 dis[to1[i]]=min(dis[u],d[to1[i]]);
40                 if(!exist[to1[i]]){
41                     p.push(to1[i]);
42                     exist[to1[i]]=1;
43                 }
44             }
45     }
46 }
47 int main(){
48     scanf("%d%d",&n,&m);
49     for(int i=1;i<=n;++i)
50         scanf("%d",&d[i]);
51     for(int i=1;i<=m;++i){
52         scanf("%d%d%d",&a,&b,&c);
53         if(c==1){
54             add1(a,b);
55             add2(b,a);
56         }
57         else{
58             add1(a,b);
59             add1(b,a);
60             add2(b,a);
61             add2(a,b);
62         }
63     }
64     dfs(n);
65     spfa();
66     for(int i=1;i<=n;++i)
67         ans=max(ans,d[i]-dis[i]);
68     printf("%d",ans);
69     return 0;
70 }
View Code

其实个人感觉这两种做法差不多。

原文地址:https://www.cnblogs.com/jsawz/p/6829077.html