zoukankan      html  css  js  c++  java
  • P1948 [USACO08JAN]电话线Telephone Lines

    原题链接  https://www.luogu.org/problem/P1948

    简化题意:

    给你一个无向图,让你去掉 k 条边后求 1~n 所经过路径中的最大边最小是多少 。

    解题思路:

    看到这个问法,是二分没错了!关键是怎么二分 。

    按照一般的套路,我们直接二分答案,那么这里就二分这个最大边!

    既然我们二分的这条边是最小的最大边,也就是说不会再经过任何比这条边还大的边了;

    为了防止经过那些比它大的边,我们可以利用那 k 次免费机会 。

    一个炒鸡敲庙的思路:

    我们将所有比我们二分出来的这条边大的边的值暂时赋成 1,其余的赋成 0(代码里用 now 表示),我们从点 1 跑一次最短路,那么 dis [ n ] 就是从 1 到 n 所花费的最少免费次数 。

    判断我们二分的这一条边是否合法,就可以看看 dis [ n ] 和 k 的大小关系:

    如果 dis [ n ] <= k,说明这是一个合法的方案,我们可以继续往小里二分;否则要往大里二分!

    其实也不是很难嘛qwq

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<cstring>
    using namespace std;
    int read()
    {
        char ch=getchar();
        int a=0,x=1;
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') x=-x;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            a=(a<<1)+(a<<3)+(ch-'0');
            ch=getchar();
        }
        return a*x;
    }
    const int inf=1e9;
    int n,m,k,l,r,ans,edge_sum;
    int u[10001],v[10001],w[10001],dis[10001],vis[10001],head[10001];
    struct node
    {
        int now,dis,from,to,next;                //now是存这条边和我们二分的mid的大小关系的,不懂的往下看看就好了 
    }a[100001];
    void add(int from,int to,int dis)            //链表建边 
    {
        edge_sum++;
        a[edge_sum].from=from;
        a[edge_sum].to=to;
        a[edge_sum].dis=dis;
        a[edge_sum].next=head[from];
        head[from]=edge_sum;
    }
    bool check(int x)                            //SPFA判断合法性 
    {
        queue<int> q;
        for(int i=1;i<=n;i++)                    //注意初始化 
        {
            dis[i]=inf;
            vis[i]=0;
        }
        for(int i=1;i<=edge_sum;i++)
        {
            if(a[i].dis>x) a[i].now=1;           //把比mid大的边设为1 
            else a[i].now=0;                     //其他的设为0 
        }
        dis[1]=0;
        q.push(1);
        vis[1]=0;
        while(!q.empty())         
        {
            int f=q.front();
            q.pop();
            vis[f]=0;
            for(int i=head[f];i;i=a[i].next)
            {
                int zd=a[i].to;
                if(dis[zd]>dis[f]+a[i].now)      //注意这里用到的是now 
                {
                    dis[zd]=dis[f]+a[i].now;
                    if(!vis[zd])
                    {
                        vis[zd]=1;
                        q.push(zd);
                    }
                }
            }
        }
        if(dis[n]<=k) return 1;                  //看看用的免费次数是否小于k 
        else return 0;
    }
    int main()
    {
        n=read();m=read();k=read();              //n个点,m条边,k次免费机会 
        l=1e9;
        for(int i=1;i<=m;i++)                  
        {
            u[i]=read();v[i]=read();w[i]=read();
            add(u[i],v[i],w[i]);                 //注意建双向边 
            add(v[i],u[i],w[i]);
            l=min(l,w[i]);                       //找二分枚举的上下界 
            r=max(r,w[i]);
        }
        while(l<=r)                              //二分答案 
        {
            int mid=(l+r)>>1;
            if(check(mid)) r=mid-1,ans=mid;
            else l=mid+1;
        }
        if(ans==0) printf("-1");                 //如果没有找到答案,就是无解 
        else printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    BZOJ 3555: [Ctsc2014]企鹅QQ hash
    bzoj 4300: 绝世好题 dp
    Codeforces Round #192 (Div. 1) C. Graph Reconstruction 随机化
    Codeforces Round #192 (Div. 1) B. Biridian Forest 暴力bfs
    Codeforces Round #192 (Div. 1) A. Purification 贪心
    HDU 5514 Frogs 容斥定理
    HDU 5515 Game of Flying Circus 二分
    HDU 5521 Meeting 最短路
    HDU 5510 Bazinga 暴力匹配加剪枝
    HDU 5512 Meeting 博弈论
  • 原文地址:https://www.cnblogs.com/xcg123/p/11385403.html
Copyright © 2011-2022 走看看