E-免费的飞机

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

 

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

 

思路:

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

spfa写法:

E-免费的飞机
#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写法:

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

E-免费的飞机
#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

 

上一篇:清北学堂(2019 5 2上午) part 5


下一篇:POJ2449 Remmarguts' Date A*算法