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 }
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 }
其实个人感觉这两种做法差不多。