• JZOJ 4320. 【NOIP2015模拟11.5】旅行


    题目

    思路

    不想写了,直接使用

    没错,关键就在求第 (k) 小的路径
    上述提到堆的做法,我们可以用 (STL) 的优先队列来实现
    只不过常数有点大~~~

    (Code)

    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    
    const int N = 1e5 + 5;
    int n , k , h[N] , tot , cnt1 , cnt2;
    LL a[N] , b[N];
    
    struct edge{
    	int to , nxt , w;
    }e[N << 1];
    
    struct node{
    	int l , r;
    	LL d;
    	bool operator < (node c) const {return d > c.d;}
    };
    
    priority_queue<node> Q;
    
    inline void add(int x , int y , int z)
    {
    	e[++tot].to = y;
    	e[tot].w = z;
    	e[tot].nxt = h[x];
    	h[x] = tot;
    }
    
    inline void dfs(int x , int fa , int fl , LL D , int ad)
    {
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == fa) continue;
    		D = D + 1LL * fl * e[i].w;
    		if (ad) a[++cnt1] = D;
    		else b[++cnt2] = -D;
    		dfs(v , x , -fl , D , ad ^ 1);
    		D = D - 1LL * fl * e[i].w;
    	}
    }
    
    int main()
    {
    	freopen("travel.in" , "r" , stdin);
    	freopen("travel.out" , "w" , stdout);
    	scanf("%d%d" , &n , &k);
    	int u , v , w;
    	for(register int i = 1; i < n; i++) 
    	{
    		scanf("%d%d%d" , &u , &v , &w);
    		add(u , v , w) , add(v , u , w);
    	}
    	b[++cnt2] = 0;
    	dfs(1 , 0 , 1 , 0 , 1);	
    	sort(a + 1 , a + cnt1 + 1) , sort(b + 1 , b + cnt2 + 1);
    	for(register int i = 1; i <= cnt1; i++) Q.push((node){i , 1 , a[i] + b[1]});
    	node now;
    	for(register int i = 1; i <= k; i++)
    	{	
    		if (Q.size())
    		{
    			now = Q.top() , Q.pop();
    			if (i == k)
    			{
    				printf("%lld" , now.d);
    				return 0;
    			}
    			if (now.r + 1 <= cnt2) Q.push((node){now.l , now.r + 1 , a[now.l] + b[now.r + 1]});
    		}
    		else{
    			printf("Stupid Mike");
    			return 0;
    		}
    	}
    }
    

    对于此类问题,我们还有一个很经典的做法
    二分答案,然后判断路径组合中比这个答案小的能不能达到 (k)
    后半句可以再套个二分实现

    (Code)

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    
    const int N = 1e5 + 5;
    int n , k , h[N] , tot , cnt1 , cnt2;
    LL a[N] , b[N];
    
    struct edge{
    	int to , nxt , w;
    }e[N << 1];
    
    inline void add(int x , int y , int z)
    {
    	e[++tot].to = y;
    	e[tot].w = z;
    	e[tot].nxt = h[x];
    	h[x] = tot;
    }
    
    inline void dfs(int x , int fa , int fl , LL D , int ad)
    {
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == fa) continue;
    		D = D + 1LL * fl * e[i].w;
    		if (ad) a[++cnt1] = D;
    		else b[++cnt2] = -D;
    		dfs(v , x , -fl , D , ad ^ 1);
    		D = D - 1LL * fl * e[i].w;
    	}
    }
    
    inline int check(LL m)
    {
    	int l , r , mid , res , sum = 0;
    	for(register int i = 1; i <= cnt1; i++)
    	{
    		l = 1 , r = cnt2 , res = 0;
    		while (l <= r)
    		{
    			mid = (l + r) >> 1;
    			if (b[mid] + a[i] <= m) res = mid , l = mid + 1;
    			else r = mid - 1;
    		}
    		sum += res;
    	}
    	return sum >= k;
    }
    
    int main()
    {
    	freopen("travel.in" , "r" , stdin);
    	freopen("travel.out" , "w" , stdout);
    	scanf("%d%d" , &n , &k);
    	int u , v , w;
    	for(register int i = 1; i < n; i++) 
    	{
    		scanf("%d%d%d" , &u , &v , &w);
    		add(u , v , w) , add(v , u , w);
    	}
    	b[++cnt2] = 0;
    	dfs(1 , 0 , 1 , 0 , 1);	
    	sort(a + 1 , a + cnt1 + 1) , sort(b + 1 , b + cnt2 + 1);
    	if ((LL)cnt1 * cnt2 < k)
    	{
    		printf("Stupid Mike");
    		return 0;
    	}
    	LL l = a[1] + b[1] , r = a[cnt1] + b[cnt2] , mid , res = l;
    	while (l <= r)
    	{
    		mid = (l + r) >> 1;
    		if (check(mid)) res = mid , r = mid - 1;
    		else l = mid + 1;
    	}
    	printf("%lld" , res);
    }
    

    实际上这两做法各有优劣
    如果要求前 (k) 的话显然用堆,它的过程本质上就是取出了前 (k) 的数

  • 相关阅读:
    Android 获取自带浏览器上网记录
    android 中的 ViewPager+ Fragment
    Git分支操作
    图形验证码的识别
    mac平台搭建安卓开发环境
    [报错集合]Uncaught ReferenceError: xxx is not defined
    Centos安装Python3
    VSCode 代码格式化 快捷键
    Mac下用Parallels Desktop安装Ubuntu
    请求头headers
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/13441847.html
Copyright © 2020-2023  润新知