【图论训练】出行

出行

trip.pas/c/cpp

 

【题目描述】

某人打算外出旅游,他从起点城市1出发,计划到达城市n。城市之间被一些航线连通, 航线可以从任意方向飞行。由于是航空公司会员,他获得一次半价(半价以后价格只保留整数部分)机票的折扣券,使用的时机可以任意安排。

【输入】

输入第一行包含两个数n, m,表示城市数量和航线数量。

接下来的m行每行有3个数ai, bi, wi,分别表示第i条航线连接的第一个城市和第二个城市,以及航线的费用。

【输出】

输出一个整数,表示路途中花费的最小值。

【输出样例】

3 3

1 2 3

2 3 4

3 1 8

 

【输出样例】

4

 

【样例解释】

直接从 1号城市飞到3号城市并出示折扣券是最优方案

 

【数据规模】

对于30%的数据,n<=100,m<=100

对于50%的数据,n<=1000,m<=1500

对于所有数据,2<=n<=10000, 1<=m<=100000, 1<=ai, bi<=n, wi<=10000,1<=n<=m。

保证存在一条路径可以从城市1到城市n的飞行方案

 

求最短距离,算法可以用spfa,只是多了两种情况(裸的spfa只有一种情况),代码中有注释

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
struct node{
    int to,next;
    int value;
}e[200005];
int head[100001];
int t=0;
int queue[100001];
int q_head=0,q_tail=1;
bool v[100001];
int f[100001];
int e_dis[100001];
int dis[100001];
void add(int u,int v,int w)
{
    t++;
    e[t].to=v;
    e[t].value=w;
    e[t].next=head[u];
    head[u]=t;
}
void read()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        add(a,b,w);
        add(b,a,w);
    }
}
void spfa()
{
    memset(v,0,sizeof(v));
    memset(dis,0x7f7f7f,sizeof(dis));
    memset(e_dis,0x7f7f7f,sizeof(e_dis));
    dis[1]=0;
    e_dis[1]=0;
    v[1]=1;
    queue[q_tail]=1;
    while(q_tail>q_head)
    {
        int p=queue[++q_head];
        v[p]=0;
        int p1=head[p];
        while(p1!=0)
        {
            bool flag=1;
            if(dis[e[p1].to]>dis[p]+e[p1].value)
            {
                dis[e[p1].to]=dis[p]+e[p1].value;//在e[p1].to及其之前都不使用半价券的情况; 
                flag=0;
            }
                     
            if(e_dis[e[p1].to]>e_dis[p]+e[p1].value){
                e_dis[e[p1].to]=e_dis[p]+e[p1].value;//在e[p1].to之前使用半价券的情况; 
                flag=0;
            } 
            if(e_dis[e[p1].to]>dis[p]+e[p1].value/2) 
            {
                e_dis[e[p1].to]=dis[p]+e[p1].value/2;//在e[p1].to使用半价券的情况; 
                flag=0;
            }//这两步是在选择最优的、在e[p1].to及其之前使用半价券的情况; 
            if(!flag&&!v[e[p1].to])//如果松弛过(一定要加入这个判断!)并不在队列中,加入队列; 
            {
                queue[++q_tail]=e[p1].to;
                v[e[p1].to]=1;
            }                
            p1=e[p1].next;
        }
    }
    return;
}
int main()
{
    freopen("trip.in","r",stdin);
    freopen("trip.out","w",stdout);
    read();
    spfa();
    printf("%d",e_dis[n]);
    return 0;
}
View Code

 

posted @ 2015-10-26 16:53  Oranges  阅读(198)  评论(0编辑  收藏  举报