Fire Department has DP practice, and if you look at the topic by provincial difficulty level it should be DP
Yesterday, we discussed with Feng Shen that if we set the right on a point, then only DP can do it.
Detailed explanations in the DP section below are reproduced from luogu CaptainSlow ( This is his blog)
DP[i][state] represents I current subtree root node A state is a state of one state = 0, 1, 2 : DP[i][0] indicates I is chosen as fire station DP[i][1] indicates that {at least} one of the sons selected I is a fire station DP[i][2] indicates that {at least} one of the grandchildren selected I is a fire station ===================================================The above three states are i {must be covered by the fire department} state = 3, 4 : DP[i][3] indicates that i's {all} son nodes must be covered by the fire department DP[i][4] indicates that i's {all} grandchild nodes must be covered by the fire department =============================================The above two states are i {not necessarily covered by the fire department}
(j, k below represent i's son node)
DP[i][0] = 1 + Σ min ( DP[j][0...4] ); Since it doesn't matter if my son and grandson are fire stations after i is a fire station, the state looks for a MIN in 0-4 and then needs +1 (because they are fire stations) DP[i][1] = min ( DP[k][0] + Σ ( j != k ) min ( DP[j][0...3] ) ); Since only brothers can be covered when a son is a fire station (excluding the son of the selected son), so that all nodes in the subtree, including his own, will be covered when a son is selected, all sons of other sons must be covered except this selected son, and the status 0-3 is satisfied. DP[i][2] = min ( DP[k][1] + Σ ( j != k ) min ( DP[j][0...2] ) ); To make it legal after selecting a grandchild, since grandchildren can only cover the current node at most, the other sons must cover all of them, with status 0~2 satisfied DP[i][3] = Σ min(DP[j][0...2]); To cover all the sons and grandchildren, that is, to cover the sons themselves, state 0~2 is satisfied DP[i][4] = Σ min(DP[j][0...3]); All grandchildren are covered, status 0~3 satisfied
Acceleration: DP[i][j] Express min ( DP[i][0..k] ) (2<=k<=4)
//So you can get:
DP[i][0] = 1 + Σ DP[j][4];
DP[i][1] = DP[i][4] + min ( DP[k][0] - DP[k][3] );
DP[i][2] = DP[i][3] + min ( DP[k][1] - DP[k][2] );
DP[i][3] = Σ DP[j][2];
DP[i][4] = Σ DP[j][3];
Correct DP is psychic, difficult to design and impossible to do
We can talk greedily and still answer the question A
Let's pick any point as a root and calculate the depth of each point
Since the deepest point must be covered, the best place to think of it is its grandfather
Why not its brother?Because you're the deepest point, setting it up on your grandfather will cover your brother,
But if the brothers don't cover Grandpa's grandpa, the greed is proven to be correct
Find the deepest point in each priority queue
AC code:
#include<bits/stdc++.h> using namespace std ; const int MAXN = 1010; struct Edge{ int nxt,to; }edge[MAXN<<1]; int head[MAXN],ectr; void addedge(int from,int to){ edge[++ectr].to = to; edge[ectr].nxt = head[from]; head[from] = ectr; } int n,dep[MAXN],father[MAXN],book[MAXN]; struct Node{ int ID,dep; }; priority_queue<Node> q; bool operator < (Node a,Node b){ return a.dep < b.dep; } void dfs1(int x,int fa){ dep[x] = dep[fa] + 1; father[x] = fa; for(int i=head[x];i;i=edge[i].nxt){ int to = edge[i].to; if(to == fa) continue; dfs1(to,x); } } int find (int x,int now){ if(x == 1 || now == 0) return x; else return find(father[x],now-1); } void tatoo(int x,int fa,int now){ book[x] = true; if(now == 0) return; for(int i=head[x]; i; i=edge[i].nxt){ int to = edge[i].to; if(to == fa) continue; tatoo(to, x, now - 1); } } int main(){ cin>>n; for(int i=2;i<=n;++i){ int aa; cin>>aa; addedge(aa,i); addedge(i,aa); } for(int i=head[1]; i; i=edge[i].nxt){ int to = edge[i].to; dfs1(to,1); } for(int i=1;i<=n;i++){ Node xxx;xxx.ID = i; xxx.dep = dep[i]; q.push(xxx); } long long ans = 0; while(!q.empty()){ Node xxx = q.top(); q.pop(); if(book[xxx.ID]) continue; ++ans; int se = find(xxx.ID,2); // cout<<"ans = "<<ans<<" se = "<<se<<endl; tatoo(se,-1,2); } cout<<ans<<endl; return 0; }
There is also a question of doing the same thing, and only greedy people can call a general order
Put the AC code here, which is a few variables short of the name above
General's Mandate#include<bits/stdc++.h> using namespace std ; const int MAXN = 100010; struct Edge{ int nxt,to; }edge[MAXN<<1]; int head[MAXN],ectr; void addedge(int from,int to){ edge[++ectr].to = to; edge[ectr].nxt = head[from]; head[from] = ectr; } int n,k,t,dep[MAXN],father[MAXN],book[MAXN]; struct Node{ int ID,dep; }; priority_queue<Node> q; bool operator < (Node a,Node b){ return a.dep<b.dep; } void dfs1(int x,int fa){ dep[x] = dep[fa] + 1; father[x] = fa; for(int i=head[x];i;i=edge[i].nxt){ int to = edge[i].to; if(to == fa) continue; dfs1(to,x); } } int find (int x,int now){ if(x == 1 || now == 0) return x; else return find(father[x],now-1); } void tatoo(int x,int fa,int now){ book[x] = true; if(now == 0) return; for(int i=head[x];i;i=edge[i].nxt){ int to = edge[i].to; if(to == fa) continue; tatoo(to, x, now - 1); } } int main(){ cin>>n>>k>>t; for(int i=1;i<n;++i){ int a,b; cin>>a>>b; addedge(a,b); addedge(b,a); } for(int i=head[1];i;i=edge[i].nxt){ int to = edge[i].to; dfs1(to,1); } for(int i=1;i<=n;i++){ Node xxx;xxx.ID = i; xxx.dep = dep[i]; q.push(xxx); } long long ans = 0; while(!q.empty()){ Node xxx = q.top(); q.pop(); if(book[xxx.ID]) continue; ++ans; int se = find(xxx.ID,k); tatoo(se,-1,k); } // cout<<find(3,1); cout<<ans<<endl; return 0; }