• 最优贸易(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
  • 相关阅读:
    三大范式
    html 横线的代码
    CSS下拉 菜单3.27第一次
    JS页面三种打开方式及对话框
    函数整理
    3.22整理作业
    for循环,if 练习
    php测试题
    设计模式
    面向对象的三大特性
  • 原文地址:https://www.cnblogs.com/sszywq/p/13934048.html
Copyright © 2020-2023  润新知