• E-免费的飞机


    题目链接:https://ac.nowcoder.com/acm/contest/699/E

    题目意思:有n个飞机场,给你起点s,终点e,有m种带权的无向边飞机线路。有k个线路,可以从中选一个免费飞行。问是否使用免费飞机票,并输出最短路花费。

    思路:

    1.先建普通飞机线路,算出最短路。再每一条免费线路重新算一次最短路,再判断是否比之前小。

    spfa写法:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    struct node{
        int u,v,w,next;
    }e[2050];
    int head[1050],vis[1050],d[1050];
    int st,ed,n,m,k,cnt;
    int from[1050],to[1050],val[1050];
    void add(int u,int v,int w)
    {
        e[cnt].u=u;
        e[cnt].v=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        head[u]=cnt++;
    }
    
    void spfa()//spfa算最短路 
    {
        memset(d,0x3f,sizeof(d));
        memset(vis,0,sizeof(vis));
        queue<int> q;
        vis[st]=1;
        d[st]=0;
        q.push(st);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int v=e[i].v;
                if(d[v]>d[u]+e[i].w)
                {
                    d[v]=d[u]+e[i].w;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
    }
    
    int main()
    {
        int u,v,w;
        cnt=0;
        memset(head,-1,sizeof(head));
        std::ios::sync_with_stdio(false);
        cin>>n>>st>>ed>>m;
        for(int i=1;i<=m;i++)
        {
            cin>>from[i]>>to[i]>>val[i];
            add(from[i],to[i],val[i]);
            add(to[i],from[i],val[i]);
        }
        spfa();
        int ans=d[ed];//记录没有用免费机票的最短路 
        int anss=inf;
        cin>>k;
        for(int i=0;i<k;i++)
        {
            cin>>u>>v;
            add(u,v,0);
            add(v,u,0);
            spfa();//每条免费线路算一次最短路 
            anss=min(anss,d[ed]);
            cnt=0;
            memset(head,-1,sizeof(head));//记得初始化 
            for(int i=1;i<=m;i++)
            {
                add(from[i],to[i],val[i]);
                add(to[i],from[i],val[i]);
            }
        }
        if(ans==anss)
            cout<<"No"<<endl<<ans<<endl;
        else
            cout<<"Yes"<<endl<<anss<<endl;
        return 0;
    }
    View Code

    dijkstra写法:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define inf 0x3f3f3f3f
    #include<queue>
    using namespace std;
    typedef long long ll;
    struct node{
        int u,v,w,next;
    }e[2050];
    struct nd{
        int id;
        int dis;
        bool operator <(const nd &a)const{
            return a.dis<dis;
        }
    };
    int head[1050],vis[1050],d[1050];
    int st,ed,n,m,k,cnt;
    int from[1050],to[1050],val[1050];
    void add(int u,int v,int w)
    {
        e[cnt].u=u;
        e[cnt].v=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        head[u]=cnt++;
    }
    void dij()//优先队列优化 
    {
        priority_queue<nd> q;
        memset(d,0x3f,sizeof(d));
        memset(vis,0,sizeof(vis));
        d[st]=0;
        while(!q.empty())
            q.pop();
        q.push({st,0});
        while(!q.empty())
        {
            nd t=q.top();
            q.pop();
            int u=t.id;
            if(vis[u])
                continue;
            vis[u]=1;
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int v=e[i].v;
                if(!vis[v]&&d[v]>d[u]+e[i].w)
                {
                    d[v]=d[u]+e[i].w;
                    q.push({v,d[v]});
                }
            }
        }
    }
    
    int main()
    {
        int u,v,w;
        cnt=0;
        memset(head,-1,sizeof(head));
        std::ios::sync_with_stdio(false);
        cin>>n>>st>>ed>>m;
        for(int i=1;i<=m;i++)
        {
            cin>>from[i]>>to[i]>>val[i];
            add(from[i],to[i],val[i]);
            add(to[i],from[i],val[i]);
        }
        dij();
        int ans=d[ed];
        int anss=inf;
        cin>>k;
        for(int i=0;i<k;i++)
        {
            cin>>u>>v;
            add(u,v,0);
            add(v,u,0);
            dij();
            anss=min(anss,d[ed]);
            cnt=0;
            memset(head,-1,sizeof(head));
            for(int i=1;i<=m;i++)
            {
                add(from[i],to[i],val[i]);
                add(to[i],from[i],val[i]);
            }
        }
        if(ans==anss)
            cout<<"No"<<endl<<ans<<endl;
        else
            cout<<"Yes"<<endl<<anss<<endl;
        return 0;
    }
    View Code

    2.开始就算出起点到所有点的最短距离和终点到所有点的最短路,在每次免费线路直接判断是否小就可以。因为是无向边,可以直接算终点到所有点的距离,如果是有向边,只要反向建边再算即可。这个思路只算了两次最短路,明显是上面快很多的。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define inf 0x3f3f3f3f
    #include<queue>
    using namespace std;
    typedef long long ll;
    struct node{
        int u,v,w,next;
    }e[2050];
    struct nd{
        int id;
        int dis;
        bool operator <(const nd &a)const{
            return a.dis<dis;
        }
    };
    int head[1050],vis[1050],d[1050][1050];
    int st,ed,n,m,k,cnt;
    void add(int u,int v,int w)
    {
        e[cnt].u=u;
        e[cnt].v=v;
        e[cnt].w=w;
        e[cnt].next=head[u];
        head[u]=cnt++;
    }
    void dij(int start)
    {
        priority_queue<nd> q;
        memset(vis,0,sizeof(vis));
        d[start][start]=0;
        while(!q.empty())
            q.pop();
        q.push({start,0});
        while(!q.empty())
        {
            nd t=q.top();
            q.pop();
            int u=t.id;
            if(vis[u])
                continue;
            vis[u]=1;
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int v=e[i].v;
                if(!vis[v]&&d[start][v]>d[start][u]+e[i].w)
                {
                    d[start][v]=d[start][u]+e[i].w;
                    q.push({v,d[start][v]});
                }
            }
        }
    }
    
    int main()
    {
        int u,v,w,flag=0;
        cnt=0;
        memset(head,-1,sizeof(head));
        std::ios::sync_with_stdio(false);
        cin>>n>>st>>ed>>m;
        for(int i=1;i<=m;i++)
        {
            cin>>u>>v>>w;
            add(u,v,w);
            add(v,u,w);
        }
        memset(d,0x3f,sizeof(d));
        dij(st);//算出起点到所有点的最短路。 
        int ans=d[st][ed];
        dij(ed);//算出终点到所有点的最短路 
        int anss=inf;    
    //    for(int i=1;i<=n;i++)
    //        cout<<i<<' '<<d[st][i]<<' '<<d[ed][i]<<endl;
        cin>>k;
    
        for(int i=0;i<k;i++)
        {
            cin>>u>>v;
            if(ans>d[st][u]+d[ed][v]||ans>d[st][v]+d[ed][u])//判断是否用免费机票 
            {
                anss=min(anss,min(d[st][u]+d[ed][v],d[st][v]+d[ed][u]));
                flag=1;
            }    
        }
        if(!flag)
            cout<<"No"<<endl<<ans<<endl;
        else
            cout<<"Yes"<<endl<<anss<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    在vue项目中引用element-ui时 让el-input 获取焦点的方法
    vue cli 平稳升级webapck4
    如何在 vuex action 中获取到 vue 实例
    Vue主要原理最简实现与逻辑梳理
    vue自定义指令clickoutside扩展--多个元素的并集作为inside
    关于使用element中的popup问题
    教你如何检查一个函数是否为JavaScript运行时环境内建函数
    用 Vue 做一个简单的购物app
    vue 手机键盘把底部按钮顶上去
    基于Linux的智能家居的设计(2)
  • 原文地址:https://www.cnblogs.com/xiongtao/p/10744889.html
Copyright © 2020-2023  润新知