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

浙公网安备 33010602011771号