您的位置:首页 > 其它

道路重建(记忆化搜索+贪心)

2017-08-18 23:02 204 查看

道路重建(记忆化搜索+贪心)

一、题目

道路重建

时间限制: 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 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: