消防局的设立&&将军令//贪心

消防局有DP做法,而且要是按省选难度看的话那个题应该是DP

昨天跟冯神讨论了一下,如果点上设权,那么就只能DP做了

下面DP部分的详细讲解转载自luogu CaptainSlow 的题解(这里是他的博客

DP[i][state] 表示 i 当前子树根节点
state就是一个一个的状态
state = 0, 1, 2 :
DP[i][0] 表示 选 i 为消防局
DP[i][1] 表示 {至少} 选了 i 的一个儿子为消防局 DP[i][2] 表示 {至少} 选了 i 的一个孙子为消防局 ==================================以上三种状态是 i {一定被消防局覆盖} 的情况 state = 3, 4 : DP[i][3] 表示 i 的 {所有} 儿子节点一定被消防局覆盖 DP[i][4] 表示 i 的 {所有} 孙子节点一定被消防局覆盖 ==================================以上两种状态是 i {不一定被消防局覆盖} 的情况

以下j, k均表示i的儿子节点)
DP[i][0] = 1 + Σ min ( DP[j][0...4] ); 由于当 i 为消防站之后儿子和孙子是否为消防局就无关紧要,因此状态在0~4中寻找一个MIN,然后还需要+1(因为自己是消防局) DP[i][1] = min ( DP[k][0] + Σ ( j != k ) min ( DP[j][0...3] ) ); 由于儿子为消防站时只能覆盖到兄弟(这里不含所选儿子的儿子),要使选了一个儿子之后子树中包括自己的所有节点都被覆盖,所以除了这个选的儿子,其他儿子的儿子一定要全部被覆盖,状态0~3满足。 DP[i][2] = min ( DP[k][1] + Σ ( j != k ) min ( DP[j][0...2] ) ); 要使选了一个孙子之后合法,由于孙子最多只能覆盖到当前节点,所以其他儿子一定全部覆盖, 状态0~2满足 DP[i][3] = Σ min(DP[j][0...2]); 要使儿子及孙子全部被覆盖,即儿子本身要被覆盖,状态0~2满足 DP[i][4] = Σ min(DP[j][0...3]); 孙子全部被覆盖 ,状态0~3满足
加速:令 DP[i][j] 表示 min ( DP[i][0..k] ) (2<=k<=4)
 因此可以得到:
 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];

正确DP很神,很难设计状态,不太可做

我们可以口胡一个贪心,照样可以A这道题

我们随便pick一个点为根,然后算出每个点的深度

由于深度最深的点必须被覆盖,所以想到覆盖掉它的最好位置就是它的爷爷

为什么不是它的兄弟?因为你是最深的点,设在你的爷爷上必能覆盖你的兄弟,

但是设在兄弟上覆盖不到爷爷的爷爷,从正确性上讲,贪心得到证明

每次用优先队列找深度最大的点

AC代码:

#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;
}

  同时有一道同做法的题,而且只能贪心,叫将军令

  这里贴出AC代码,跟上面差了几个变量名的事

#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;
}
将军令

猜你喜欢

转载自www.cnblogs.com/SINXIII/p/11261794.html