Establishment of Fire Department &&General Order//Greed

Keywords: PHP

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

#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;
}
General's Mandate

 

 


Posted by pixy on Sun, 28 Jul 2019 16:50:11 -0700