机房测试3:三角tri(dp预处理+二分+dfs剪枝)

题目:

分析:

考虑最暴力的暴搜,怎么才能优化呢?

如果我们确切地知道第k大的路径权值和有多大,那么在dfs里面加一个限制就可以求出所有前k大的路径了。

很显然答案是满足单调性的。

可以二分一个答案,dfs一遍,看满足这个答案的有多少条路径,如果超过k条,就往大的走。

最后把二分出来的答案跑一遍dfs,输出路径即可。

时间复杂度:O(log(n*n)*玄学dfs)

#include<bits/stdc++.h>
using namespace std;
#define N 1005
#define ri register int
int n,k,cnt=0,a[N][N],fl=false,lim,tot,dp[N][N],way[N];
int read()
{
    int x=0,fl=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) fl=-1; ch=getchar(); }
    while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x*fl;
}
void dfs(int x,int y,int sum)
{
    if(tot>=k) return ;
    if(sum+dp[x][y]<lim) return ;
    if(x==n){
        tot++;
        if(fl){
            for(ri i=1;i<=n-1;++i) if(way[i]==0) printf("L"); else printf("R");
            printf("\n");
        }
        return ;
    }
    way[x]=0;
    dfs(x+1,y,sum+a[x][y]);
    way[x]=1;
    dfs(x+1,y+1,sum+a[x][y]);
}
int main()
{
    freopen("tri.in","r",stdin);
    freopen("tri.out","w",stdout);
    n=read(); k=read();
    for(ri i=1;i<=n;++i)
     for(ri j=1;j<=i;++j)
      a[i][j]=read();
    for(ri i=1;i<=n;++i) dp[n][i]=a[n][i];
    for(ri i=n-1;i>=1;--i)
     for(ri j=1;j<=i;++j)
      dp[i][j]=max(a[i][j]+dp[i+1][j],a[i][j]+dp[i+1][j+1]);
    int l=0,r=1000*1000+1;
    while(l+1<r){
        int mid=(l+r)>>1;
        lim=mid, tot=0, dfs(1,1,0);
        if(tot>=k) l=mid;
        else r=mid;
    }
    tot=0; lim=l; fl=true;
    dfs(1,1,0);
}
/*
3 3
1
1 100
2 1 1

10 6
1
2 3
4 3 2
3 4 5 6
3 2 4 6 5
7 6 8 4 6 5
3 5 6 3 2 7 4
3 4 5 6 7 3 5 3
2 4 5 6 7 4 6 4 2
2 4 5 6 7 4 6 4 2 4
*/

原文地址:https://www.cnblogs.com/mowanying/p/11623473.html

时间: 2024-10-05 23:25:36

机房测试3:三角tri(dp预处理+二分+dfs剪枝)的相关文章

hdu 4791 dp预处理+二分

题意: 打印东西,给出区间(张数)对应费用(到达一定张数就都按某更低的价格),m次询问,问最优费用.给的时候按张数递增给的. dp出当前张数到最后的最小值.对于询问q,然后二分处>=q的最小的一个张数的价格.min(这个价格*p,dp[这+1])即可.nlogn;后来看网上有些人用线段树,没必要的. ps:开始竟然因为犯中间数据爆int的初级错误!,不该不该! #include<iostream> #include<vector> #include<algorithm&

机房测试11:最小生成树(最小生成树+二分)

题目: 分析: 如果直接做最小生成树,会出现以下不合法情况: 1.白边选多了.说明白边的权值太小了,我们可以通过加大白边的权值来似的选少一点白边. 2.白边选少了.与上面同理. 我们不知道白边的取值在多少合适,但明显具有单调性(白边权值越大,选的条数一定会减少),所以可以用二分来确定白边的取值. 二分一个取值,将所有白色边权减去mid,做一遍最小生成树,如果能选到>=need条边,就把mid增大. 细节: 1. =need也要把mid增大. 2. 不能只在白边恰好选到need的时候更新答案,这时

hdu--(1025)Constructing Roads In JGShining&#39;s Kingdom(dp/LIS+二分)

Constructing Roads In JGShining's Kingdom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 16047    Accepted Submission(s): 4580 Problem Description JGShining's kingdom consists of 2n(n is no mor

[九省联考2018]林克卡特树(DP+wqs二分)

对于k=0和k=1的点,可以直接求树的直径. 然后对于60分,有一个重要的转化:就是求在树中找出k+1条点不相交的链后的最大连续边权和. 这个DP就好.$O(nk^2)$ 然后我们完全不可以想到,将best[k](选择k条链的答案)打表输出,更不可能然后作差分,发现得到的数组是递减的. 这说明:best[k]是一个上凸包. 于是我们可以二分一个斜率去切这个凸包(类似导数),根据切点横坐标与k的大小旋转直线(改变斜率). 考虑给你一个直线斜率k,怎么找到它和凸包的切点.实际上就相当于将这个凸函数减

nyoj 325 zb的生日 【DP】||【DFS】

两种方法: 第一种:将总数一半当做背包,用总数-2*最多能装的数目就是所求: 第二种:深搜: zb的生日 时间限制:3000 ms  |  内存限制:65535 KB 难度:2 描述 今天是阴历七月初五,acm队员zb的生日.zb正在和C小加.never在武汉集训.他想给这两位兄弟买点什么庆祝生日,经过调查,zb发现C小加和never都很喜欢吃西瓜,而且一吃就是一堆的那种,zb立刻下定决心买了一堆西瓜.当他准备把西瓜送给C小加和never的时候,遇到了一个难题,never和C小加不在一块住,只能

[BZOJ 1082] [SCOI2005] 栅栏 【二分 + DFS验证(有效剪枝)】

题目链接:BZOJ - 1082 题目分析 二分 + DFS验证. 二分到一个 mid ,验证能否选 mid 个根木棍,显然要选最小的 mid 根. 使用 DFS 验证,因为贪心地想一下,要尽量先用提供的小的木木棍,尽量先做出需要的大的木棍,所以要先将提供的木棍和需要的木棍都排序. DFS 的时候是按照需要的木棍从大到小的顺序一层一层搜,每一层上是按照从小到大的顺序枚举提供的木棍.(当然枚举的时候已经不一定是从小到大了,有些木棍已经被截掉了一些.) 要使用两个有效的剪枝: 1)如果下一层的木棍和

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

51nod1307(暴力树剖/二分&amp;dfs/并查集)

题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307 题意: 中文题诶~ 思路: 解法1:暴力树剖 用一个数组 num[i] 维护编号为 i 的边当前最大能承受的重量. 在加边的过程中根据给出的父亲节点将当前边所在的链上所有边的num都减去当前加的边的重量, 注意当前边也要减自重. 那么当num首次出现负数时加的边号即位答案: 事实上这个算法的时间复杂度是O(n^2)的, 不过本题并没有出那种退化成单链的

百练1088:滑雪 【DP】+【DFS】

总Time Limit: 1000ms Memory Limit: 65536kB Description Michael喜欢滑雪百这并不奇怪, 由于滑雪的确非常刺激.但是为了获得速度,滑的区域必须向下倾斜,并且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道载一个区域中最长的滑坡.区域由一个二维数组给出.数组的每一个数字代表点的高度.以下是一个 样例 1  2  3  4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 1