• 【NOI模拟赛】寄(树形DP)


    题面

    在这里插入图片描述
    在这里插入图片描述

    题解

    找出最近的中转站可以直接转化为随便匹配一个中转站。

    树形DP,这个没什么好说的。

    主要是状态怎么设计。

    正解以及大部分人设计的状态非常⭐,所以不需要什么别的东西直接可过。

    但是我设计了个不太好的 DP:

    d p 1 [ i ] [ j ] dp_1[i][j] dp1[i][j] 表示在 i i i 的子树内,目前有 j j j 个关键点无主,子树内所有边贡献和的最小值。 d p 2 [ i ] [ j ] dp_2[i][j] dp2[i][j] 表示在 i i i 子树总共有 j j j 个关键点要连进来,子树所有边贡献和的最小值。

    合并两个子树 x , y x,y x,y 时,两个 DP 可以分别单独背包转移,除此之外, d p 2 [ x ] [ i ] dp_2[x][i] dp2[x][i] 还可以从 d p 2 [ x / y ] [ i + j ] + d p 1 [ y / x ] [ j ] + . . . dp_2[x/y][i+j]+dp_1[y/x][j]+... dp2[x/y][i+j]+dp1[y/x][j]+... 转移过来。贪心的想,我们只需要往外的需求吞掉无主的需求,这时候无主的关键点一定不用多出来。最后再讨论一下在子树的根处设中转站。

    但是有个小问题:每个子树的状态数都是抵满 O ( n ) O(n) O(n) 的,虽然 d p 1 dp_1 dp1 的复杂度可以保证是 O ( n 2 ) O(n^2) O(n2) ,但是 d p 2 dp_2 dp2 O ( n 3 ) O(n^3) O(n3) 的。再次利用贪心技巧:子树外的需求总量不会超过子树内关键点总数,不然中转站可以上移。

    时间复杂度 O ( n 2 ) O(n^2) O(n2)

    CODE

    #include<map>
    #include<set>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<random>
    #include<bitset>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<unordered_map>
    #pragma GCC optimize(2)
    using namespace std;
    #define MAXN 3005
    #define LL long long
    #define ULL unsigned long long
    #define ENDL putchar('\n')
    #define DB double
    #define lowbit(x) (-(x) & (x))
    #define FI first
    #define SE second
    #define PR pair<int,int>
    int xchar() {
    	static const int maxn = 1000000;
    	static char b[maxn];
    	static int pos = 0,len = 0;
    	if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
    	if(pos == len) return -1;
    	return b[pos ++];
    }
    // #define getchar() xchar()
    LL read() {
    	LL f = 1,x = 0;int s = getchar();
    	while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
    	while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
    	return f*x;
    }
    void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
    void putnum(LL x) {
    	if(!x) {putchar('0');return ;}
    	if(x<0) putchar('-'),x = -x;
    	return putpos(x);
    }
    void AIput(LL x,int c) {putnum(x);putchar(c);}
    
    int n,m,s,o,k;
    int hd[MAXN],nx[MAXN<<1],v[MAXN<<1],w[MAXN<<1],cne;
    void ins(int x,int y,int z) {
    	nx[++cne] = hd[x]; v[cne] = y; hd[x] = cne; w[cne] = z;
    }
    LL dp[MAXN][MAXN],dp2[MAXN][MAXN],td[MAXN],td2[MAXN];
    int siz[MAXN],ct[MAXN],C;
    void dfs(int x,int ff) {
    	siz[x] = ct[x];
    	for(int i = 0;i <= n;i ++) dp[x][i] = 1e18,dp2[x][i] = 1e18;
    	dp[x][0] = C; dp[x][ct[x]] = 0;
    	for(int i = 0;i <= ct[x];i ++) dp2[x][i] = C;
    	for(int ii = hd[x];ii;ii = nx[ii]) {
    		int y = v[ii],W = w[ii]; if(y == ff) continue;
    		dfs(y,x);
    		for(int i = siz[x];i >= 0;i --) {
    			td[i] = dp[x][i],td2[i] = dp2[x][i];
    			dp[x][i] = 1e18; dp2[x][i] = 1e18;
    		}
    		for(int i = siz[x];i >= 0;i --) {
    			for(int j = siz[y];j >= 0;j --) {
    				dp[x][i+j] = min(dp[x][i+j],td[i] + dp[y][j] + W*1ll*j);
    				dp2[x][i+j] = min(dp2[x][i+j],td2[i] + dp2[y][j] + W*1ll*j);
    			}
    			for(int j = 0;j <= siz[y] && j <= i;j ++) {
    				dp2[x][i-j] = min(dp2[x][i-j],td2[i] + dp[y][j] + W*1ll*j);
    			}
    		}
    		for(int i = siz[y];i >= 0;i --) {
    			for(int j = 0;j <= siz[x] && j <= i;j ++) {
    				dp2[x][i-j] = min(dp2[x][i-j],dp2[y][i] + W*1ll*i + td[j]);
    			}
    		}
    		siz[x] += siz[y];
    	}
    	LL mn = 1e18;
    	for(int i = 0;i <= siz[x];i ++) mn = min(mn,dp[x][i] + C);
    	dp2[x][0] = dp[x][0] = min(min(dp2[x][0],dp[x][0]),mn);
    	for(int i = 1;i <= siz[x];i ++) dp2[x][i] = min(dp2[x][i],mn);
    	return ;
    }
    int main() {
    	freopen("post.in","r",stdin);
    	freopen("post.out","w",stdout);
    	n = read(); m = read(); C = read();
    	for(int i = 1;i < n;i ++) {
    		s = read();o = read();k = read();
    		ins(s,o,k); ins(o,s,k);
    	}
    	for(int i = 1;i <= m;i ++) {
    		ct[read()] ++;
    	}
    	dfs(1,0);
    	AIput(dp[1][0],'\n');
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
  • 相关阅读:
    计算机网络--HTTP 协议的请求方式 GET 和 POST
    NanoPC-T4 Debian buster root用户自动登录
    git从入门到会用
    Linux中bind9的view(视图解析)配置示例与注意事项
    关于在 Linux 下多个不相干的进程互斥访问同一片共享内存的问题
    CSS三栏布局的7种方式代码详解 | 圣杯布局 | 双飞翼布局 | 弹性盒子
    用于gin框架的CORS中间件,解决身份凭证和通配符不能同时设置问题,可同时配置附带身份凭证的请求和*通配符,chrome插件CORS跨域请求通配符
    城市道路拥堵终结者,智能停车场系统组网解决方案
    Java成员内部类、局部内部类、匿名内部类
    安全生产:CVE-2020-11022/CVE-2020-11023漏洞解析
  • 原文地址:https://blog.csdn.net/weixin_43960414/article/details/125432202