南华大学第十五届ACM程序设计竞赛(重现赛) E 免费机票

这是一道来源于牛客网的编程竞赛题目,描述了小飞赢得一张限定区间的免费飞机票,他需要从s地出发到e地,但可能需要转机且要考虑费用。问题转化为在k个区间中找到最便宜的转机路线。解决方法是建立图并使用最短路径算法,注意在每次运行迪杰斯特拉算法时要删除已使用的免费边,因为只能选择一条免费路径。
摘要由CSDN通过智能技术生成

链接:https://ac.nowcoder.com/acm/contest/699/E
来源:牛客网
 

题目描述

        某华大学小飞中奖了!!!奖品是一张免费飞机票,唯一遗憾的是,这张飞机票有限定区间,需要从k个区间中选择其一。小飞打算高高兴兴的出去玩啦,但是,从s地出发,去往e地,可能没有直达的飞机票,可能需要转机(所有飞机线路都是无向的),小飞毕竟是个学生党,出去玩首先得考虑省钱,所以,小飞遇到麻烦了,请帮小飞计算最便宜的一条路线,小飞会很感激你的。

输入描述:

第一行为三个整数n,s,e,n表示n个不同城市的飞机场,s为出发点,e为目的地。(1<=n<=1000,  1<=s,e<=n)

第二行为一个整数m,表示m条普通飞机线路,接下来的m行描述每条线路,每行包含三个整数a、b、c,a、b代表普通飞机线路两端,c表示价格。(1<=m<=1000,  1<=a,b<=n,  1<=c<=1000)

接下来的一行为一个整数k,表示k个免费机票的航线区间, 然后k行来描述每条免费航线,每行两个整数a’、b’,    分别代表免费航线两端。(1<=k<=1000,  1<=a’,b’<=n)

输出描述:

每个测试数据有两行输出,第一行为是否使用免费飞机票,是则输出“Yes”,否则输出“No”。第二行输出总共花费。

示例1

输入

复制

4 1 4
3
1 2 1
1 3 2
2 4 3
1
3 4

输出

复制

Yes
2

示例2

输入

复制

7 1 7
5
1 4 1
1 5 2
1 7 10
4 7 8
5 7 5
2
2 4
6 7

输出

复制

No
7

我的思路很简单,就是建完图之后跑一次最短路,然后再分别跑k次,对比一下就行了

有个地方要注意的是,在你加过一次免费边 跑完dijk的时候,要把这个边删掉,再加剩下的

因为题目要求只能选k中的一条

代码写的比较丑。。。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+5;
const int maxm=1e4+5;
int head[maxn],vis[maxn],cnt,n,m,s,ee;
ll dis[maxn];
struct edge
{
    int to,next,dis;
}e[maxm];
void addedge(int u,int v,int w)
{
    cnt++;
    e[cnt].to=v;
    e[cnt].dis=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
struct node
{
    int pos;ll dis;
    bool operator <(const node &x)const
    {
        return x.dis<dis;
    }
};
priority_queue<node>q;
inline void dijkstra()
{
    for(int i=1;i<=n;i++) dis[i]=0x3f3f3f3f;
    dis[s]=0;
    q.push((node){s,0});
    while(!q.empty())
    {
        node tmp=q.top();
        q.pop();
        int x=tmp.pos;
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i;i=e[i].next)
        {
            int y=e[i].to;
            if(dis[y]>dis[x]+e[i].dis)
            {
                dis[y]=dis[x]+e[i].dis;
                if(!vis[y])
                 
                    q.push((node){y,dis[y]});
                 
            }
        }
    }
}
int uu[maxn],vv[maxn],ww[maxn]; int cntt;
int main()
{
    scanf("%d%d%d%d",&n,&s,&ee,&m);
    for(int i=0;i<m;i++)
    {
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
        addedge(v,u,w);
        uu[cntt]=u,vv[cntt]=v,ww[cntt]=w;cntt++;
    }
    dijkstra();
    ll ans=dis[ee];
    ll anss=0x3f3f3f3f;
    int k;scanf("%d",&k);
    for(int i=0;i<k;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        int x=e[head[u]].to;  int y=e[head[u]].to;
        addedge(u,v,0);
        addedge(v,u,0);
        memset(vis,0,sizeof vis);
        dijkstra();
        anss=min(anss,dis[ee]);
         
        memset(head,0,sizeof head);
        memset(e,0,sizeof e);
        cnt=0;
        for(int j=0;j<cntt;j++)  addedge(uu[j],vv[j],ww[j]),addedge(vv[j],uu[j],ww[j]);
    }
    if(ans!=anss) printf("Yes\n%d\n",min(ans,anss));
    else  printf("No\n%d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值