一、题目
道路重建
时间限制: 1 Sec 内存限制: 128 MB
提交: 9 解决: 6
题目描述
现在有一棵n个结点的树(结点从1到n编号),请问至少要删除几条边,才能得到一个恰好有p个结点的子树?
输入
第一行输入两个数n和p (1 <= n<= 150, 1 <= p<=n)
接下来输入n-1行,每行两个整数x y,表示x和y之间有一条边。
输出
输出答案。
样例输入
11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11
样例输出
2
提示
如果1-4 和 1-5 两条边删除,结点1, 2, 3, 6,
7, 8会形成一颗有6个结点的子树。
来源
二、分析
1 #include <iostream>
2 #include <algorithm>
3 using namespace std;
4
5 struct node{
6 int nameNum;//nameNum表示节点的编号
7 int val;//val表示节点i的所有孩子(包括直接和间接)与它本身之和
8 };
9 struct node a[155];//用a[i].val表示节点i的所有孩子(包括直接和间接)与它本身之和
10 bool vis[155];//vis[i]==false表示节点i没有被访问过
11 bool adjacencyMatrix[155][155];//adjacencyMatrix[i][j]=true表示i是j的父亲
12 int n,p;
13 int fatherSum[155];//fatherSum[i]表示congi节点出发到它的祖先,经过的节点数,也就是它和他所有祖先的和
14 int father[155][155];//father[i][j]记录i号节点的第j个父亲 //记忆化搜索,把所有找过的节点的父亲都记录下来
15
16 int minStep;
17 int choose[155];//记录所有被选的边
18 int ans[155];
19
20 bool operator <(node p1,node p2){
21 return p1.val>p2.val;
22 }
23
24 void printArr();
25 void printArr_a();
26 void printArr_ans();
27
28 void readData(){
29 cin>>n>>p;
30 int father1,child1;
31 for(int i=1;i<n;i++){
32 cin>>father1>>child1;
33 a[father1].nameNum=father1;
34 a[child1].nameNum=child1;
35 //记录直接孩子的数目
36 //a[father1].val++;
37 adjacencyMatrix[father1][child1]=true;
38 }
39 }
40
41
42 //记忆化搜索,把所有找过的节点的父亲都记录下来
43 //回溯找i的所有父亲,给它的所有父亲的a[i]加1
44 void findFather(int child){
45 if(child==1) return;
46 for(int i=1;i<=n;i++){
47 if(adjacencyMatrix[i][child]){
48 a[i].val++;
49 father[child][0]=father[i][0]+1;
50 father[child][father[child][0]]=i;
51 if(father[i][0]!=0){//说明i节点的父亲我已经找过了
52 for(int j=1;j<=father[i][0];j++){
53 father[child][j]=father[i][j];
54 a[father[i][j]].val++;
55 }
56 }
57 else findFather(i);
58 break;
59 }
60 }
61 }
62
63 //填充数组a
64 void findArr_a(){
65 for(int i=1;i<=n;i++){//对1-n这n个节点找父亲
66 a[i].val++;
67 findFather(i);
68 }
69 }
70
71 void init(){
72 readData();
73 findArr_a();//回溯法找a[i]
74 //printArr_a();
75 //printArr();
76 }
77
78 //下一次搜索的时候,我肯定没有必要再从n开始搜索
79 //如果前minstep根都达不到长度,那么所有后面的都不用看了,所以minStep的初始值就是n
80 //如果这一根和上一根相同,如果上一根不可以,那么这一根也不用尝试了
81 void search(int m,int step,int start){
82 if(m==0){
83 if(step<minStep){
84 minStep=step;
85 for(int i=1;i<=minStep;i++){
86 ans[i]=choose[i];
87 }
88 }
89
90 }else
91 for(int i=start;i<=n;i++){
92 //如果step大于等于了minStep,它及它后面的都不用考虑了
93 if(step>=minStep) return;
94
95 //如果在choose里面有他的父亲,那他就不用考虑了
96 int findFather=false;
97 // for(int j=1;j<=step;j++){
98 // for(int k=1;k<=father[a[i].nameNum][0];k++){
99 // if(choose[j]==father[a[i].nameNum][k]){
100 // findFather=true;
101 // }
102 // }
103 // }
104 for(int j=1,k=1;j<=step&&k<=father[a[i].nameNum][0];){
105 if(choose[j]==father[a[i].nameNum][k]){
106 findFather=true;
107 break;
108 }else if(choose[j]<father[a[i].nameNum][k]){
109 j++;
110 }else if(choose[j]>father[a[i].nameNum][k]){
111 k++;
112 }
113 }
114 if(findFather) continue;
115
116 //如果这一根和上一根相同,如果上一根不可以,那么这一根也不用尝试了
117 if(i>1&&a[i].val==a[i-1].val&&!vis[i-1]) continue;
118
119 //如果前minstep根都达不到长度,那么所有后面的都不用看了,所以minStep的初始值就是n
120 if(minStep!=n){
121 int sum=0;
122 int k=minStep;
123 int i1=i;
124 while(k--){
125 sum+=a[i1++].val;
126 }
127 if(sum<m) return;
128 }
129
130 if(!vis[i]&&a[i].val<=m){
131 vis[i]=true;
132 choose[step+1]=a[i].nameNum;
133 search(m-a[i].val,step+1,i+1);
134 }
135 vis[i]=false;
136 }
137 }
138
139 void findans(){
140 int m=n-p;
141 minStep=n;
142 search(m,0,1);
143 cout<<minStep<<endl;
144 printArr_ans();
145 }
146
147 int main() {
148 freopen("src/test8.txt","r",stdin);
149 //freopen("src/test2.txt","r",stdin);
150 //freopen("src/RoadRebuild.txt","r",stdin);
151 init();
152 sort(a+1,a+n+1);
153 //printArr_a();
154 findans();
155 return 0;
156 }
157
158 void printArr_ans(){
159 for(int i=1;i<=minStep;i++){
160 cout<<ans[i]<<" ";
161 }
162 cout<<endl;
163 }
164
165 void printArr_a(){
166 for(int i=1;i<=n;i++){
167 cout<<a[i].val<<" "<<a[i].nameNum<<" ";
168 }
169 cout<<endl;
170 }
171
172 void printArr(){
173 cout<<"Arr a"<<endl;
174 cout<<"--------------------------------------------------------------------"<<endl;
175 for(int i=1;i<=n;i++){
176 cout<<a[i].val<<" ";
177 }
178 cout<<endl;
179
180 cout<<"Arr fatherSum"<<endl;
181 cout<<"--------------------------------------------------------------------"<<endl;
182 for(int i=1;i<=n;i++){
183 cout<<fatherSum[i]<<" ";
184 }
185 cout<<endl;
186
187
188 cout<<"Arr vis"<<endl;
189 cout<<"--------------------------------------------------------------------"<<endl;
190 for(int i=1;i<=n;i++){
191 cout<<vis[i]<<" ";
192 }
193 cout<<endl;
194
195 cout<<"Arr adjacencyMatrix"<<endl;
196 cout<<"--------------------------------------------------------------------"<<endl;
197 for(int i=1;i<=n;i++){
198 for(int j=1;j<=n;j++){
199 cout<<adjacencyMatrix[i][j]<<" ";
200 }
201 cout<<endl;
202 }
203 cout<<endl;
204
205 cout<<"Arr father"<<endl;
206 cout<<"--------------------------------------------------------------------"<<endl;
207 for(int i=1;i<=n;i++){
208 for(int j=1;j<=father[i][0];j++){
209 cout<<father[i][j]<<" ";
210 }
211 cout<<endl;
212 }
213 cout<<endl;
214
215 }
我的旨在学过的东西不再忘记(主要使用艾宾浩斯遗忘曲线算法及其它智能学习复习算法)的偏公益性质的完全免费的编程视频学习网站: fanrenyi.com;有各种前端、后端、算法、大数据、人工智能等课程。
一些博文中有一些参考内容因时间久远找不到来源了没有注明,如果侵权请联系我删除。
博主25岁,前端后端算法大数据人工智能都有兴趣。