• 道路和航线,题解


    题目:

    题意:

      题目说的简洁明了,有两种路,一种没负数,一种没环,求单元最短路。

    分析:

      spfa随便优化(双端队列)一下水过。。。

      当然这好像并不是正解。。。

      其实看到这一题,相信大家都能想到类似缩点的做法,有很明显的暗示,所有我们直接考虑将双向边所连的点缩成一个,然后就是个有向无环图,然后再跑非常好想到拓扑排序,然后没有入度之后就可以安心的跑dij去贪心了。

      说一下,有同学说:我直接给所有边加上一个较大的数字,然后最后再减去,跑dij就好了。。。注意dij的贪心思想是怎么来的,这样。。。显然不好。

      又有人说,你这样处理不还是会有负权吗。。。

      还是要弄明白dij的贪心思想怎么来的,没有负权边就好啦,dis可以是负数。

      最后就是两个代码。

      

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int maxn=25000+10;
    struct E{
        int to;
        int next;
        int val;
        E(){
            val=to=next=0;
        }
    }ed[maxn*6];
    int head[maxn];
    int tot;
    deque<int> q;
    int vis[maxn];
    int dis[maxn];
    void J(int a,int b,int c){
        tot++;
        ed[tot].to=b;
        ed[tot].val=c;
        ed[tot].next=head[a];
        head[a]=tot;
    }
    int main(){
        int T,R,P,S;
        memset(dis,0x3f,sizeof(dis));
        scanf("%d%d%d%d",&T,&R,&P,&S);
        int js1,js2,js3;
        for(int i=1;i<=R;i++){
            scanf("%d%d%d",&js1,&js2,&js3);
            J(js1,js2,js3);
            J(js2,js1,js3);
        }
        for(int i=1;i<=P;i++){
            scanf("%d%d%d",&js1,&js2,&js3);
            J(js1,js2,js3);
        }
        vis[S]=1;
        q.push_back(S);
        dis[S]=0;
        while(!q.empty()){//直接spfa
            int s=q.front();
            q.pop_front();
            vis[s]=0;
            for(int i=head[s];i;i=ed[i].next){
                if(vis[ed[i].to])
                    dis[ed[i].to]=min(dis[ed[i].to],dis[s]+ed[i].val);
                else{
                    if(dis[ed[i].to]>dis[s]+ed[i].val){
                        dis[ed[i].to]=dis[s]+ed[i].val;
                        vis[ed[i].to]=1;
                        if(q.empty())//注意判空
                            q.push_back(ed[i].to);
                        else if(dis[ed[i].to]>=dis[q.front()])//小小优化
                            q.push_back(ed[i].to);
                        else
                            q.push_front(ed[i].to);
                    }
                }
            }
        }
        for(int i=1;i<=T;i++)
            if(dis[i]>=1e9)
                printf("NO PATH
    ");
            else
                printf("%d
    ",dis[i]);
    }
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    const int maxn=25000+10;
    struct E{
        int to;
        int next;
        bool x;//记录是什么样的边
        int val;
        E(){
            to=next=x=val=0;
        }
    }ed[maxn*6];
    int head[maxn];
    int tot;//
    void J(int a,int b,int c,bool d){
        tot++;
        ed[tot].to=b;
        ed[tot].val=c;
        ed[tot].x=d;
        ed[tot].next=head[a];
        head[a]=tot;
    }
    int js;//记录缩成的点数
    int bel[maxn];//记录点属于哪个缩之后的点
    int rd[maxn];//记录缩之后的点的入度
    int vis[maxn];//dij用的数组
    vector<int> ve[maxn];//记录每个缩之后的点所包含的点
    void Dfs(int x){//缩点
        ve[js].push_back(x);
        bel[x]=js;
        for(int i=head[x];i;i=ed[i].next)
            if(!bel[ed[i].to])
                Dfs(ed[i].to);
    }
    struct Node{
        int dis;
        int x;
        Node(){
        }
        Node(int a,int b){
            dis=a;
            x=b;
        }
        friend bool operator < (Node a,Node b){
            return a.dis>b.dis;
        }
    };
    queue<int> qu;//拓扑排序用
    priority_queue<Node> que[maxn];//dij用
    int dis[maxn];//dij用
    void Dij(int x){
        while(!que[x].empty()){
            Node js=que[x].top();
            que[x].pop();
            if(vis[js.x])
                continue;
            vis[js.x]=1;
            for(int i=head[js.x];i;i=ed[i].next){
                if(!ed[i].x)//注意特判
                    continue;
                if(dis[ed[i].to]>dis[js.x]+ed[i].val){
                    dis[ed[i].to]=dis[js.x]+ed[i].val;
                    que[x].push(Node(dis[ed[i].to],ed[i].to));
                }
            }
        }
    }
    int main(){
        int T,R,P,S;
        scanf("%d%d%d%d",&T,&R,&P,&S);
        int js1,js2,js3;
        for(int i=1;i<=R;i++){
            scanf("%d%d%d",&js1,&js2,&js3);
            J(js1,js2,js3,1);
            J(js2,js1,js3,1);
        }
        for(int i=1;i<=T;i++)//缩点
            if(!bel[i]){
                js++;
                Dfs(i);
            }
        for(int i=1;i<=P;i++){
            scanf("%d%d%d",&js1,&js2,&js3);
            J(js1,js2,js3,0);
            rd[bel[js2]]++;
        }
        memset(dis,0x3f,sizeof(dis));
        for(int i=1;i<=js;i++)
            if(rd[i]==0)
                qu.push(i);
        dis[S]=0;
        que[bel[S]].push(Node(0,S));
        while(!qu.empty()){
            int s=qu.front();
            qu.pop();
            Dij(s);
            for(int i=0;i<ve[s].size();i++)
                for(int j=head[ve[s].at(i)];j;j=ed[j].next){//这里可以不特判
                    rd[bel[ed[j].to]]--;
                    if(dis[ve[s].at(i)]+ed[j].val<dis[ed[j].to]){
                        dis[ed[j].to]=dis[ve[s].at(i)]+ed[j].val;
                        que[bel[ed[j].to]].push(Node(dis[ed[j].to],ed[j].to));
                    }
                    if(rd[bel[ed[j].to]]==0)
                        qu.push(bel[ed[j].to]);
                }
        }
        for(int i=1;i<=T;i++)
            if(dis[i]>=1e9-1)
                printf("NO PATH
    ");
            else
                printf("%d
    ",dis[i]);
        return 0;
    }
  • 相关阅读:
    LOL 战斗力查询
    D3js-对柱状图的增,删,排序
    我的项目7 js 实现歌词同步(额,小小的效果)
    为什么电脑启动任务管理器会这样
    OpenCV求取轮廓线
    leetcode-Reverse Words in a String
    Linux lvs DR配置
    p2p网贷3种运营模式
    T4308 数据结构判断
    1080 线段树练习
  • 原文地址:https://www.cnblogs.com/wish-all-ac/p/12806708.html
Copyright © 2020-2023  润新知