F. Economic Difficulties
题目链接:
https://codeforces.com/contest/1263/problem/F
题目大意:
两棵树,都有n个叶子节点,一棵树正着放,一棵树倒着放,叶子节点从左到右对应装置1,2,3,4...n,问最多能删掉多少条边,使得装置能与两棵树任意一个根节点1相连。
解题思路:
mp[ i ][ j ]是装置 i 到 j 这段区间删除这段连续区间所能删除的最大边数,两个图分开看,算出每一个图中如果不连通这段区间对应的叶子节点所能删除的最大边数,取这两个图的最大值就是mp[ i ][ j ]。dp[ i ]代表前 i 个装置中的最大删除数,因此可以推出递推式dp[ i ]=max(dp[ i ],dp[j] + mp[ j ][ i ] ) 其中j是从0 - i。
代码:
1 #include <bits/stdc++.h>
2 using namespace std;
3 const int N=3e3;
4 const int maxn=1e9+7;
5 const int minn=0;
6 vector<int>arr[N];//存图
7 int sz[N];//记录当删除这个点后最多能删除多少条边
8 int L[N],R[N];//记录第i个节点包含的设备区间中的最左端与最右端
9 int mp[N][N];//记录选取任意连续区间的设备并删除,可以删除最多几条边(连续是指删除的边在同一个图中)
10 int dp[N];
11
12 int dfs(int a,int pre){
13 if(a!=1){//每个点都代表他上方的那条边,1的上方没有边
14 sz[a]=1;
15 }
16 for(int i=0;i<arr[a].size();i++){
17 if(arr[a][i]!=pre){
18 dfs(arr[a][i],a);
19 sz[a]+=sz[arr[a][i]];//记录删除这个点会删除多少条边
20 L[a]=min(L[a],L[arr[a][i]]);//这个点代表区间的左端点
21 R[a]=max(R[a],R[arr[a][i]]);//右端点
22 }
23 }
24 mp[L[a]][R[a]]=max(mp[L[a]][R[a]],sz[a]);//记录这个区间的最大删除边数
25 }
26
27 int main(){
28 int n,a,b,v;
29 cin>>n;
30 for(int i=0;i<2;i++){
31 scanf("%d",&a);
32 for(int i=1;i<=N;i++){
33 arr[i].clear();
34 L[i]=maxn;//初始化无穷大
35 R[i]=minn;//0
36 }
37 for(int i=1;i<a;i++){//存图
38 scanf("%d",&v);
39 arr[v].push_back(i+1);
40 arr[i+1].push_back(v);
41 }
42 for(int i=1;i<=n;i++){
43 scanf("%d",&v);//这个点代表的装置区间为i
44 R[v]=L[v]=i;
45 }
46 sz[1]=0;
47 dfs(1,0);
48 }
49 dp[0]=0;
50 dp[1]=mp[1][1];
51 for(int i=2;i<=n;i++){
52 for(int j=0;j<=i;j++){
53 dp[i]=max(dp[i],dp[j]+mp[j+1][i]);
54 }
55 }
56 cout<<dp[n]<<endl;
57 return 0;
58 }