P1272 重建道路

P1272 重建道路

题目描述

一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。因此,牧场运输系统可以被构建成一棵树。John想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有P(1≤P≤N)个牲口棚的子树和剩余的牲口棚分离,John想知道这些道路的最小数目。

输入输出格式

输入格式:

第1行:2个整数,N和P

第2..N行:每行2个整数I和J,表示节点I是节点J的父节点。

输出格式:

单独一行,包含一旦被破坏将分离出恰含P个节点的子树的道路的最小数目。

输入输出样例

输入样例#1:

11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

输出样例#1:

2

说明

【样例解释】

如果道路1-4和1-5被破坏,含有节点(1,2,3,6,7,8)的子树将被分离出来

分析:

用 dp[i][j] 表示以i节点为根,截出含有j个点的连通子树所需要截的最少次数。

那么可以得到初始化 dp[i][1]=du[i] (du[i]为i的入边与出边的总和),意思是只选i这一个节点,那么当然要把与它相连的边都截掉。

那么状态转移方程怎么得到呢

以样例为例子,节点1连接 2,3,4,5 。节点2连接 6,7,8。递归着进行动规之后我们可以得到 dp[2][3]=2 (截取1-2和2-8)

那么dp[1][4]=min(dp[1][4],dp[2][3]+dp[1][1]-2)

为啥要减2

因为dp[1][1]是删了一次 1-2 的结果,dp[2][3]也删了一次 1-2,但事实上得到dp[1][4]时 1-2是连通的,所以把这删的两次补上。

具体动规按照分组背包的循环顺序跑。

状态转移方程:

dp[u][j]=min(dp[u][j],dp[u][k]+dp[v][j-k]-2);

从父亲节点选k个,从儿子节点选j-k个。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define ll long long
 7 #define M(a) memset(a,0,sizeof a)
 8 #define fo(i,j,k) for(i=j;i<=k;i++)
 9 using namespace std;
10 const int mxn=155;
11 vector <int> f[mxn];
12 int n,p;
13 int dp[mxn][mxn],du[mxn];
14 inline void dfs(int u)
15 {
16     int i,j,k,v,x=f[u].size()-1;
17     //包含出度和入度
18     dp[u][1]=du[u];
19     fo(i,0,x)
20     {
21         v=f[u][i];
22         dfs(v);
23         for(j=p;j>=2;j--)
24           for(k=1;k<j;k++)
25             dp[u][j]=min(dp[u][j],dp[u][k]+dp[v][j-k]-2);
26     }
27 }
28 int main()
29 {
30     int i,j,u,v,ans=1e8;
31     scanf("%d%d",&n,&p);
32     fo(i,0,n) fo(j,0,n) dp[i][j]=200; //初始化防止加法溢出
33     fo(i,0,n) dp[i][0]=0;
34     fo(i,2,n)
35     {
36         scanf("%d%d",&u,&v);
37         f[u].push_back(v);
38         du[u]++;du[v]++;
39     }
40     dfs(1);
41     fo(i,1,n)
42       ans=min(ans,dp[i][p]);
43     printf("%d\n",ans);
44     return 0;
45 }
时间: 2024-10-06 18:17:22

P1272 重建道路的相关文章

P1272 重建道路(树形dp)

P1272 重建道路 题目描述 一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场.由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的.因此,牧场运输系统可以被构建成一棵树.John想要知道另一次地震会造成多严重的破坏.有些道路一旦被毁坏,就会使一棵含有P(1≤P≤N)个牲口棚的子树和剩余的牲口棚分离,John想知道这些道路的最小数目. 输入输出格式 输入格式: 第1行:2个整数,N和P 第2..N行:每行2个整数I和J,表示

luogu P1272 重建道路

嘟嘟嘟 这好像是一种树上背包. 我们令dp[i][j] 表示在 i 所在的子树中(包括节点 i)分离出一个大小为 j 的子树最少需割多少条边. 那么转移方程就是 dp[u][j] = min(dp[u][j], dp[u][j - k] + dp[v][k] - 1) (v是u的一个儿子) 理解起来就是在u所在子树中切 j 个节点,等于在u中切 j - k 个节点加上在v所在子树中切 k 个节点所需要切的边数之和.又因为切出来的这两部分要合并得到一个节点数为 j 的,所以要减1. 1 #incl

[Usaco2002 Feb]Rebuilding Roads重建道路

题目描述 一场可怕的地震后,奶牛用N个牲口棚(1 <= N <= 150,编号1..N)重建了农民John的牧场.奶牛没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是唯一的.因此,牧场运输系统可以被构建成一棵树.John想要知道另一次地震会造成多严重的破坏.有些道路一旦被毁坏,就会使一棵含有P(1 <= P <= N)个牲口棚的子树和剩余子牲口棚分离,John想知道这些道路的最小数目. 输入格式 第1行:2个整数, N和P 第2..N行:每行2个整数I和J,表示节

[luoguP1272] 重建道路

传送门 奇奇怪怪的分组背包. #include <cstdio> #include <cstring> #include <iostream> #define N 151 #define min(x, y) ((x) < (y) ? (x) : (y)) int n, p, cnt, ans = ~(1 << 31); int head[N], to[N], next[N], f[N][N]; inline int read() { int x = 0

重建道路

传送门 我们来看一道比较可做的树形DP. 现在这个数据规模的树形DP都是可以直接n3暴力转移过掉的呀-- 不过这个状态比较特殊,我们用dp[i][j]表示i节点在子树中保留j个节点所需要删去的最小边数. 那么转移方程就是,dp[i][j] = min(dp[i][j],dp[i][j-k] + dp[v][k] - 1);其中那个-1是节点i和节点v之间的连边,那个是要保留的orz,他之前会被重复计算. 所以我们直接这样暴力dp即可,一开始的初始化是dp[i][1] = son[i],son表示

9.12(多米诺骨牌+道路修建+重建道路)

一道dp: 有两个限制条件时可以考虑将其中一个存到维度,另外一个作为值,但一定要理清楚哪个是要优先满足的 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1002 4 int dp[N][10005],a[N],b[N],d[N]; 5 int main() 6 { 7 memset(dp,0x3f3f3f,sizeof(dp)); 8 int n; 9 scanf("%d",&n); 10

NYOJ 674 善良的国王(树形背包DP)

善良的国王 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 传说中有一个善良的国王Good,他为了不劳民伤财,每当建造一个城镇的时候都只用一条路去连接,这样就可以省很多的人力和物力,也就说如果有n个城镇,那么只需要n-1条路就可以把所有的城镇链接起来了(也就是一颗树了).但是不幸的事情发生了:有个一强大的帝国想要占领这个国家,但是由于国王Good的兵力不足,只能守护m个城镇,所以经过商量,国王Good只能从他的所有城镇中选择m个相链接的城市,并且把所有可以链接到这m

1002. [WZOI2011 S3] 周年纪念日

1002. [WZOI2011 S3] 周年纪念日 Problem 3 周年纪念日 (anniversary.pas/c/cpp) 背景 WZland即将迎来一个举国欢庆的日子—建国150亿周年纪念日,值此之际WZland有许多事情要准备…… 问题描述 WZland的国王决定举办一个晚会,这次晚会要求所有的WZland居民都参加,但是他发现WZland的所有城市之间的道路都已经毁坏(平时WZland的居民都在自己的城市里活动,所以他们对于那些道路一点都不关心).这是一件十分麻烦的事情,因为这个晚

几个树形dp

1.重建道路 树形dp基础题,f[i][j]表示在i这个点我和我的子树联通块大小为j最少砍几条边. 转移的时候,到下一个子树时上一个子树所有答案先++(此树直接砍掉不贡献答案),再继续dp. 注意更新答案时,如果不是跟答案还有+1(砍掉我和我父亲的),不然洛谷会挂四个点QAQ 马上就Noip了我还只能做这种水题QAQ 还挂 //Twenty #include<algorithm> #include<iostream> #include<cstring> #include