• P1948 [USACO08JAN]电话线Telephone Lines


    传送门

    思路:

      二分+最短路径:可以将长度小于等于 mid 的边视为长度为 0 的边,大于 mid 的边视为长度为 1 的边,最后用 dijkstra 检查 d [ n ] 是否小于等于 k 即可。

    标程:

    #include<cstring>
    #include<queue>
    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<fstream>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<stack>
    #include<map>
    #include<set>
    #include<deque>
    #include<string>
    using namespace std;
    #define maxn 100100
    #define INF 0x3f3f3f3f
    priority_queue<pair< int,int >,vector<pair<int,int> >,greater<pair<int,int > > > q;
    struct hh
    {
        int u,v,w,nex;
    }t[maxn<<1];
    int d[maxn<<1],head[maxn<<1],jla[maxn<<1];//jla记录每条边的边长 
    int n,m,p,s=1,cnt=0,ans=INF;//ans记录答案 
    bool vis[maxn<<1];
    inline int read()
    {
        int kr=1,xs=0;
        char ls;
        ls=getchar();
        while(!isdigit(ls))
        {
            if(ls=='-') 
                kr=-1;
            ls=getchar();
        }
        while(isdigit(ls))
        {
            xs=(xs<<1)+(xs<<3)+(ls^48);
            ls=getchar();
        }
        return kr*xs;
    }
    inline void add(int x,int y,int z)
    {
        t[++cnt].u=x;
        t[cnt].v=y;
        t[cnt].w=z;
        t[cnt].nex=head[x];
        head[x]=cnt;
    }//链式前向星加边 
    inline bool dijkstra(int now)
    {
        for(int i=1;i<=n;i++)
        {
            d[i]=INF;
            vis[i]=false;
        }
        d[s]=0;
        q.push(make_pair(d[s],s));
        while(!q.empty())
        {
            int k=q.top().second;
            q.pop();
            if(vis[k]) continue;
            else
            {
                vis[k]=true;
                for(int i=head[k];i!=-1;i=t[i].nex)
                {
                    if(t[i].w>now)
                        if(d[t[i].v]>d[k]+1)
                        {
                            d[t[i].v]=d[k]+1;
                            q.push(make_pair(d[t[i].v],t[i].v));
                        }//如果t[i].v的边大于当前二分的答案,那么就要使用一次名额
                    if(t[i].w<=now)
                        if(d[t[i].v]>d[k])
                        {
                            d[t[i].v]=d[k];
                            q.push(make_pair(d[t[i].v],t[i].v));
                        }//如果t[i].v的边不大于当前二分的答案,那么就无需使用名额,直接松弛操作
                }
            }
        }
        if(d[n]>p) return false;//如果到达n的次数大于免费的次数限制,那么当前答案不可行
        return true;//反之,则可行 
    }
    int main()
    {
        n=read();m=read();p=read();
        for(int i=1;i<=n;i++)
          head[i]=-1;
        int xx,yy,zz;
        for(int i=1;i<=m;i++)
        {
            xx=read();yy=read();zz=read();
            add(xx,yy,zz);
            add(yy,xx,zz);
            jla[i]=zz;
        }
        sort(jla+1,jla+m+1);//将所有的边从小到大排序,为二分做准备
        if(dijkstra(0))
        {
            printf("0
    ");
            return 0;
        }
        if(!dijkstra(jla[m]))
        {
            printf("-1
    ");
            return 0;
        }//两个特判,,, 
        int l=1,r=m;
        while(l<=r)
        {
            int mid=l+r>>1;//二分查找 
            if(dijkstra(jla[mid]))
            {
                ans=min(ans,jla[mid]);
                r=mid-1;
            }
            else l=mid+1;
        }
        printf("%d
    ",ans);//输出答案 
    return 0;
    }

      

  • 相关阅读:
    <转>浅谈DNS体系结构:DNS系列之一
    SOA和NS区别
    《浅析各类DDoS攻击放大技术》
    《转》DNS放大攻击
    Linux创建公钥
    MATLAB 中有哪些命令,让人相见恨晚
    SQL中的declare用法
    SQl server 附加数据库失败如何解决
    VS中代码对齐等快捷键
    C#窗口控件Dock的位置顺序调整方法
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9691193.html
Copyright © 2020-2023  润新知