StkOvflow

STACK OVERFLOW!

一言(ヒトコト)

辛苦了~
——lmh

AcWing340通信道路/ USACO2008 Telephone Line S

AcWing题目
洛谷题目

解题思路

首先可以得到一个很容易得到的贪心策略,将一条路径上最贵的(边权最大)的K条边删去,那么我们剩下的路径中最贵(边权最大)的路就是原本这条路径上帝K+1大的路。
于是原问题就可以转化为:
求一张无向图中最大的一条路径中的第K+1大的边
这就启发我们枚举所有的路径。
可行吗?
显然是不可行的,这个路很多,但是我们可以反向思考
我们可以假定一个距离x,然后看看这张图上是否存在一条路径,使它上面第K+1大的边长度为x,进一步的,我们可以转化成为在这张图中,是否存在K条边,任意一条边的权重Wi>x
这样我们的check函数似乎就呼之欲出了

check函数

这里的check我们判断一张图中是否有K条权重大于x的边,可以进行一下转换:
对于边权Wi>x 的边,设置权重wi=1(这是小w,不是原题给定权重)
反之设置权重wi=0
然后跑下这张图的最短路(1N),判断是否k即可

Dijkstra写法 O(mlog2n)

这没什么好说的,就是建图跑最短路,因为边权非负(只能是01

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<int, int> PII;

const int N = 20020;
int h[N], e[N], w[N], ne[N], idx;
int dist[N], st[N], n, m, k;

void add(int a, int b, int c) 
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}

bool check(int x) 
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);
    
    priority_queue<PII, vector<PII>, greater<> > heap;
    dist[1] = 0, heap.push({dist[1], 1});
    
    while (heap.size()) 
    {
        auto t = heap.top().second; heap.pop();
        
        if (st[t]) continue ;
        st[t] = true ;
        
        for (int i = h[t]; ~i; i = ne[i]) 
        {
            int j = e[i], W = (w[i] > x);
            if (dist[j] > dist[t] + W) 
            {
                dist[j] = dist[t] + W;
                heap.push({dist[j], j});
            }
        }
    }
    
    return dist[n] <= k;
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    
    memset(h, -1, sizeof h);
    while (m -- ) 
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w), add(v, u, w);
    }
    
    int l = 0, r = 1e6 + 1;
    while (l < r) 
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    if (r == 1e6 + 1) r = -1;
    printf("%d\n", r);
    
    return 0;
}

双端队列广搜 O(mlogn)

因为边权只有01,可以用双端队列广搜,时间是线性的,再乘上二分次数,是O(mlogn)

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<int, int> PII;

const int N = 20020;
int h[N], e[N], w[N], ne[N], idx;
int dist[N], st[N], n, m, k;

void add(int a, int b, int c) 
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}

bool check(int x) 
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);
    
    deque<int> dq;
    dist[1] = 0, dq.push_back(1);
    
    while (dq.size()) 
    {
        int t = dq.front(); dq.pop_front();
        
        if (st[t]) continue ;
        st[t] = true ;
        
        for (int i = h[t]; ~i; i = ne[i]) 
        {
            int j = e[i], W = (w[i] > x);
            if (dist[j] > dist[t] + W) 
            {
                dist[j] = dist[t] + W;
                if (W) dq.push_back(j);
                else dq.push_front(j);
            }
        }
    }
    
    return dist[n] <= k;
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    
    memset(h, -1, sizeof h);
    while (m -- ) 
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w), add(v, u, w);
    }
    
    int l = 0, r = 1e6 + 1;
    while (l < r) 
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    if (r == 1e6 + 1) r = -1;
    printf("%d\n", r);
    
    return 0;
}

SPFA O(mlogn)

和Dijkstra一样,跑个最短路

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<int, int> PII;

const int N = 20020;
int h[N], e[N], w[N], ne[N], idx;
int dist[N], st[N], n, m, k;

void add(int a, int b, int c) 
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++ ;
}

bool check(int x) 
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);
    
    queue<int> q;
    dist[1] = 0, q.push(1), st[1] = true;
    
    while (q.size()) 
    {
        int t = q.front(); q.pop();
        st[t] = false ;
        
        for (int i = h[t]; ~i; i = ne[i]) 
        {
            int j = e[i], W = (w[i] > x);
            if (dist[j] > dist[t] + W) 
            {
                dist[j] = dist[t] + W;
                if (!st[j]) q.push(j), st[j] = true ;
            }
        }
    }
    
    return dist[n] <= k;
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    
    memset(h, -1, sizeof h);
    while (m -- ) 
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w), add(v, u, w);
    }
    
    int l = 0, r = 1e6 + 1;
    while (l < r) 
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    if (r == 1e6 + 1) r = -1;
    printf("%d\n", r);
    
    return 0;
}

关于时间

AcWing:Dijkstra 150msBFS  56msSPFA 63ms
Luogu:Dijkstra 238ms,BFS 73msSPFA 89ms

Accepted!

posted @   StkOvflow  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示