最优贸易(SPFA)

 

 题意:在一张节点带有权值(点权)的图上找出一条从1到n的路径,使路径上能选出两个点p,q(先经过p在经过q),并且“节点q的权值减去p的权值”最大。

思路:

1. 枚举每一个节点 i ,1 ~ i 按照最短路来求,记录1 ~ i 中最短的边是 dim [ i ].

2. 反向建图,枚举每一个节点 i ,N ~ i 按照最大路来求,记录N ~ i 中最长的边是 dim [ i ].

(反向建图,这里要想明白,假设1->2->3, 我们从节点1开始跑,我们反向之后变成3->2->1,我们从节点3开始跑。

其实是一样的)。

说一下这题为什么不能用Dij , 假设存在边 5-> 6, 6-> 7, 7-> 5 。很明显这是存在环的,如果用Dij 我们假设dim[ 5 ]=10,然后6处的价格是4,更新,

但是 7处价格是 3,更新, dim[ 7 ]=3.,我么发现 7又和5相连,此时dim[5] 被更新成 3,假设 3是当前最小队列中的最小值,我们就要把 5再次取出,但是5已经被标记过了,不能再被取出,这就导致了后面的dim[ 6 ] 还是4,更新不成3.导致答案错误。(主要原因是图中存在环路,当前取出的值不一定是最小值,所以就不能用Dij)。

#include<bits/stdc++.h>
#include<cstring>
#include<string.h>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int dmin[N],dmax[N],n,m;
int w[100005];
bool vis1[N],vis2[N];
struct node{
    int to;
};
vector<node> vec1[N],vec2[N];
void spfa1()
{
    /*for(int i = 1; i <= n; ++i) cout << dmin[i] << " ";
    cout <<endl;*/

    queue<int>q;
    q.push(1);
    dmin[1]=w[1];
    vis1[1]=1;
    while(!q.empty()){
        int u=q.front();
        //cout << "u = " << u <<endl;
        q.pop();
        vis1[u]=0;
        int _size=vec1[u].size();
        for(int i=0; i<_size; i++){
            int to=vec1[u][i].to;
            if(dmin[to]>min(w[to],dmin[u])){
                dmin[to]=min(w[to],dmin[u]);
                 /*  更新最小值。用到 u 的最小的边,和 u ~ v 相连的边进行比较 */
                if(!vis1[to]){
                    q.push(to);
                    vis1[to]=1;
                }
            }
        }
    }
 //cout<<"**"<<endl;
}
void spfa2(){
   queue<int>q;
    q.push(n);
    dmin[n]=w[n];
    vis1[n]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis2[u]=0;
        int _size=vec2[u].size();
        for(int i=0; i<_size; i++){
            int to=vec2[u][i].to;
            if(dmax[to]<max(w[to],dmax[u])){
                dmax[to]=max(w[to],dmax[u]);
                  /*  更新最大值。用到 u 的最大的边,和 u ~ v 相连的边进行比较 */
                if(!vis2[to]){
                    q.push(to);
                    vis2[to]=1;
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++){
        cin>>w[i];
    }
    int x,y,z;
    for(int i=1; i<=m; i++)
    {
      scanf("%d%d%d",&x,&y,&z);
        if(z==1)
            vec1[x].push_back({y}),vec2[y].push_back({x});
        else
            vec1[x].push_back({y}),vec1[y].push_back({x}),vec2[y].push_back({x}),vec2[x].push_back({y});
    }
    memset(dmin,0x3f,sizeof (dmin));
     /*memset(vis1,0,sizeof (vis1));
     memset(vis2,0,sizeof (vis2));*/
    spfa1();
    spfa2();
    int ans=0;
    for(int i=1; i<=n; i++)
    {
       //  cout<<dmin[i]<<"  "<<dmax[i]<<endl;
        ans=max(ans,dmax[i]-dmin[i]);
    }
    printf("%d",ans);
    return 0;
}
View Code

 

posted @ 2020-11-06 20:09  Swelsh-corgi  阅读(104)  评论(0编辑  收藏  举报