• #树形dp,二分#UVA1407 Caves 洛谷 3698 [CQOI2017]小Q的棋盘


    题目

    给定一棵树,现在需要找到一条由节点1出发长度为(x)的路径,
    问最多经过的节点数,重复经过只计算一次(不一定是简单路径)
    UVA的那道题多组数据多组询问,边权还不一定是1,(nleq 500)


    分析

    (dp[x][ans][0/1])表示在以(x)为根的子树内,
    经过的节点数为(ans),当前答案的终点是否为点(x)的最短路径长度
    那么

    [dp[x][j+k][0]=min{dp[x][j][1]+dp[y][k][0]+w,dp[x][j][0]+dp[y][k][1]+w*2} ]

    [dp[x][j+k][1]=min{dp[x][j][1]+dp[y][k][1]+w*2} ]

    由于(min{dp[x][ans][0],dp[x][ans][1]})显然具有单调性,所以可以二分
    时间复杂度(O(T(n^2+Qlog_2n)))


    代码

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #define rr register
    using namespace std;
    const int N=511; struct node{int y,w,next;}e[N];
    int dp[N][N][2],siz[N],as[N],ans[N],n,Test;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline signed min(int a,int b){return a<b?a:b;}
    inline void dfs(int x){
    	dp[x][1][0]=dp[x][1][1]=0,siz[x]=1;
    	for (rr int i=as[x];i;i=e[i].next){
    		dfs(e[i].y),siz[x]+=siz[e[i].y];
    		for (rr int j=siz[x]-siz[e[i].y];j;--j)
    		for (rr int o=siz[e[i].y];o;--o){
    			dp[x][j+o][0]=min(dp[x][j+o][0],dp[x][j][1]+dp[e[i].y][o][0]+e[i].w);
    			dp[x][j+o][0]=min(dp[x][j+o][0],dp[x][j][0]+dp[e[i].y][o][1]+e[i].w*2);
    			dp[x][j+o][1]=min(dp[x][j+o][1],dp[x][j][1]+dp[e[i].y][o][1]+e[i].w*2);
    		}
    	}
    }
    signed main(){
    	while (1){
    		n=iut(); if (!n) return 0;
    		printf("Case %d:
    ",++Test);
    		memset(as,0,sizeof(as)),
    		memset(dp,42,sizeof(dp));
    		for (rr int i=1;i<n;++i){
    			rr int x=iut()+1,F=iut()+1,w=iut();
    			e[i]=(node){x,w,as[F]},as[F]=i;
    		}
    		dfs(1);
    		for (rr int i=1;i<=n;++i)
    		    ans[i]=min(dp[1][i][0],dp[1][i][1]);
    		for (rr int Q=iut();Q;--Q){
    			rr int W=iut();
    		    rr int l=1,r=n;
    		    while (l<r){
    		    	rr int mid=(l+r+1)>>1;
    		    	if (ans[mid]>W) r=mid-1;
    		    	    else l=mid;
    			}
    			print(l),putchar(10);
    		}
    	}
    } 
    
  • 相关阅读:
    【零基础】极星9.5套利详解
    【零基础】极星9.3资金字段详解
    【零基础】易盛9.0API入门三:下单并查询订单状态
    【零基础】极星量化扩展一:如何做跨合约的交易
    【零基础】极星9.3止盈止损用法详解
    【零基础】极星9.3几种套利的说明
    【零基础】MT4量化入门三:写一个双均线指标
    概率与似然
    PCA的计算方法
    隐藏节点数的选择
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14157957.html
Copyright © 2020-2023  润新知