20260729考试总结

考的不好!!!

P3243 [HNOI2015] 菜肴制作

简化题意:

\(n\) 个点,给出形似 \(A\) 必须在 \(B\) 前面的 \(m\) 条约束条件,现在需要你在当前编号最小的点尽可能靠前放的情况下,满足依赖关系。(即如果当前 \(1\) 没有进队列,且 \(1,2\) 不存在依赖关系,应该优先让 \(1\) 进入队列)。

题解:

这种存在依赖关系的很容易就想到了拓扑排序,但是这里并不是要求字典序最小,所以是不对的。转换一下,小的尽可能往前,那不就是等于大的尽可能往后吗?如果一个点 \(x\) 占据 \(n\) 的位置,其他点就不可能在占据 \(n\) 了,所以比 \(x\) 小的数也就会往前。因此我们就可以建反图,然后跑字典序最大的拓扑排序,最后倒序输出。


代码
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
vector<int>g[N];
int in[N];
int n,m;
int ans[N],top;
void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)g[i].clear(),in[i]=0;
    for(int i=1;i<=m;i++){
        int u,v;cin>>u>>v;
        g[v].push_back(u);
        in[u]++;
    }
    priority_queue<int>q;
    top=0;
    for(int i=1;i<=n;i++){
        if(!in[i])q.push(i);
    }
    while(!q.empty()){
        int u=q.top();q.pop();
        ans[++top]=u;
        for(auto i:g[u]){
            in[i]--;
            if(!in[i])q.push(i);
        }
    }
    if(top!=n)cout<<"Impossible!\n";
    else{
        for(int i=n;i>=1;i--)cout<<ans[i]<<' ';
        cout<<"\n";
    }
    return;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--)solve();
    return 0;
}

P2279 [HNOI2003] 消防局的设立

简化题意

给定一棵 \(n\) 个节点的树,可以在若干个节点作标记,请求出最少需要的标记数,使得每个节点不超过 \(2\) 的距离内会存在一个被标记的节点(距离是指经过的边数)。

题解

求最少,一般就是树上DP,或者贪心,在这里我们考虑以下贪心。

贪心思路就是寻找一个深度最大的且还未满足条件的点,然后给他的祖父打上标记,没有祖父就父节点,没有父节点就自己。


最优性证明

想让当前这个节满足条件,当且仅当在它自己,它的父节点,祖父节点打上标记。因为深度比它大的都已经满足条件了,所以我们不去考虑在它的子树内打标记。(兄弟节点因为和我们是同一层的,考虑哪个都一样,所以不参与讨论)

那么显然,我们肯定选择深度最小的节点打上标记,会使得满足条件的节点最多。


那么我们应该怎么判断他是未满足条件的呢?满足条件当且仅当:父节点,祖父节点,子节点,孙子节点,或者是同父的兄弟节点被打上了标记。除了兄弟节点其它条件都可以通过判断直接枚举判断,至于兄弟节点,我们对于每个被打上了标记的节点,可以在它的父节点上打一个不同的标记,那么直接判断父节点是否被当上了标记即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n;
int fa[N],zf[N];
int dep[N];
vector<int>g[N];
vector<int>son[N];
vector<int>sz[N];
int ans;
bool vis[N];
bool ez[N];
bool check(int u){
    for(auto i:son[u])if(vis[i])return 1;
    for(auto i:sz[u])if(vis[i])return 1;
    return 0;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;dep[1]=1;
    g[1].push_back(1);
    for(int i=2;i<=n;i++){
        cin>>fa[i];zf[i]=fa[fa[i]];
        dep[i]=dep[fa[i]]+1;
        g[dep[i]].push_back(i);
        son[fa[i]].push_back(i);
        sz[zf[i]].push_back(i);
    }
    for(int de=n;de>=1;de--){
        for(auto i:g[de]){
            if(vis[i] || vis[fa[i]] || vis[zf[i]] || ez[fa[i]] || check(i))continue;
            ans++;
            if(zf[i])vis[zf[i]]=1,ez[fa[zf[i]]]=1;
            else if(fa[i])vis[fa[i]]=1,ez[zf[i]]=1;
            else vis[i]=1,ez[fa[i]]=1;
        }
    }
    cout<<ans;
    return 0;
}
posted @ 2026-07-29 16:56  凉茶映屏红  阅读(1)  评论(0)    收藏  举报