码迷,mamicode.com
首页 > 其他好文 > 详细

Phoneline

时间:2015-08-04 17:19:29      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:noip   题解   二分   最短路   

Phoneline

Description

小h最近准备给家里新装条电话线,好让他在奥运假期能够天天上网冲浪,不用再忍受那昂贵的无线上网。 电信局的工作人员对小h说,电话线网络上有n个站点,它们用m条边来连接,小h家的站点在1号,连接的终点在n号,站点之间有电线连接,而且有一定的费用,然后因为暑期的原因,在1号站点连接到n号站点的线路上有k条线是免费的,然后在这条线路剩下的线中费用最大的为小h连接到n号站要付的费用。 当然,小h希望他要付的钱最少,于是他就出了这道题,希望有人能帮帮他。

Input

第一行: n,m,k,意义如上文所述。
以下m行,每行3个正整数s,t,cost,指从s站到t站的费用是cost.
(即t到s的费用也是cost)
注意:可能会出现重边或自环
n∈【1,1000】;m∈【1,n*(n-1)/2】
1< s,t <=n,0<=cost<=10000

Output

一个正整数,表示最小的费用。

Sample Input

5 6 1
2 1 3629
3 2 8034
4 3 7348
5 4 3689
4 4 7266
5 5 6088

Sample Output

7348


最短路+二分
找到一条从1~n的路线,使其第k+1大值最小。这个k+1大值就是答案。而求最大值最小或者最小值最大就可以用二分来完成。但是这道题还有一点区别就是对于二分的边界没有一个明确的范围,所以不妨把所有边的最大值val_max当做这个边界。
首先要处理重边和自环,这个可以用一个hash数组,或者一个邻接矩阵来记录某一条边是否出现过,如果自环直接continue;重边则要保留最小的边权。
接着二分,假设现在一共有p条边,那么我们二分1~p得到左边的【1~mid】和右边的【mid+1~p】(//这里存的是一个结构体,每一个代表一个from,to,val,next)现在不妨令左边的边权为0,右边的边权为1。现在再运行一遍最短路,如果dis[n]<=k,则在左半边重复进行上述操作。反之则在右半边进行,直到只剩下一个点。这个点的val就是答案。
为什么这样做可以呢?二分的位置代表最大值,左边的值比这个值小,右边的值比这个值大。dis[n]表示从1~n中必须经过比二分出来的值大的边的个数,如果这个值小于k,则左移,反之右移。

Attention

  • 算好内存。。。
  • 二分的两种写法,需要注意等号以及是否+1
  • 记好用了什么表示边的个数,表示方法越多越容易出错
  • 需要用到两个结构体,一个存正常的val,一个用0/1表示
  • 每次都要重新建图,所以初始化init的位置一定要注意(!!)

Code:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define MAXN 1200
using namespace std;
typedef long long ll;
struct node
{
    ll from;
    ll to;
    ll next;
    ll val;
}edge[(MAXN*MAXN)>>1];
struct node2
{
    ll from;
    ll to;
    ll next;
    ll val;
}tmp[(MAXN*MAXN)>>1];
ll n,m,k,cnt,t,l,r,mid,ans,p;
ll map[MAXN][MAXN],head[MAXN],visit[MAXN],dis[MAXN];
ll min(ll a,ll b){return a<b?a:b;}
ll cmp(node2 a,node2 b){return a.val < b.val ? 1 : 0 ;}
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1;
}
void addedge(ll from,ll to,ll val)
{
    edge[cnt].from=from;
    edge[cnt].to=to;
    edge[cnt].val=val;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
void spfa(ll src)
{
    memset(dis,0x3f,sizeof(dis));
    memset(visit,0,sizeof(visit));
    dis[src]=0;
    visit[src]=1;
    queue<int>q;
    q.push(src);
    while(q.size())
    {
        ll u=q.front();
        q.pop();
        for(ll i=head[u];i!=-1;i=edge[i].next)
        {
            ll v=edge[i].to;
            if(dis[u]+edge[i].val<dis[v])
            {
                dis[v]=dis[u]+edge[i].val;
                if(visit[v]==0)
                {
                    visit[v]=1;
                    q.push(v);
                }
            }
        }
        visit[u]=0; 
    }
}
void pre_deal(ll mid)
{
    init(); ///!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    for(ll i=1;i<=p;i++)
    {
        if(i<=mid)
        {
            addedge(tmp[i].from,tmp[i].to,0);
            addedge(tmp[i].to,tmp[i].from,0);
        }
        else
        {
            addedge(tmp[i].from,tmp[i].to,1);
            addedge(tmp[i].to,tmp[i].from,1);
        }
    }
}
ll check(ll mid)
{
    pre_deal(mid);
    spfa(1);
    if(dis[n]<=k)
    {
        return 1;
    }
    return 0;
}
ll find(ll l,ll r)
{
    ll ret=0;
    while(l<r)
    {
        ll mid=(l+r)>>1;
        if(check(mid))
        {
            r=mid;
        }else
        {
            l=mid+1;
        }
    }
    return r;
}
int main()
{
    init();
    scanf("%lld%lld%lld",&n,&m,&k);
    t=m;
    for(ll i=1;i<=m;i++)
    {
        ll a,b,c;
        scanf("%lld %lld %lld",&a,&b,&c);
        if(a==b)
            t--;
        if(map[a][b]>c&&a!=b) 
        {
            map[a][b]=c;
            continue;
        }
        if(!map[a][b]&&a!=b) 
        {
            map[a][b]=c;
        }
    }
    p=0;
    for(ll i=1;i<=n;i++)
    {
        for(ll j=1;j<=n;j++)
        {
            if(map[i][j])
            {
                ll c=map[i][j];
                tmp[++p].from=i;
                tmp[p].to=j;
                tmp[p].val=c;
            }
        }
    }   
    sort(tmp+1,tmp+p+1,cmp);    
    printf("%lld\n",tmp[find(1,p)].val);
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

Phoneline

标签:noip   题解   二分   最短路   

原文地址:http://blog.csdn.net/z_mendez/article/details/47278205

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!