关于贪心策略的一些小trick
为什么要写这种如此简单的东西呢 就是因为菜啊
首先给出关于贪心的三个定义
符合贪心选择的特性(Greedy Choice Property)
我们需要证明我们的第一个选择(贪心选择 Greedy Choice,First Choice)包含在某些最优解中
符合归纳法结构(Inductive Structure)
我们需要证明第一个选择(贪心选择)之后,子问题和原问题还是同一类问题,意味着我们的选择不改变问题的结构,
并且子问题的解可以和第一个选择(贪心选择)合并
最优子结构(Optimal Substructure)
如果我们可以最优的解决子问题,我们可以将子问题的解和贪心选择得到原问题的解
(以上摘自
先谈谈我自己的理解
上面的专业术语看着都应该头大才对,那怎么说会让它变得简单一些呢,我们从一个简单地例子来解释上面的第一条和第三条。
现在
搬出我么喜闻乐见的反证法:假设当前版本并不比之前的强,那么对于之前的版本,查莉雅最多可以做到同时给自己和队友套盾,而当前版本的查莉雅显然也可以做到,这便是“我们需要证明我们的第一个选择(贪心选择 Greedy Choice,First Choice)包含在某些最优解中”,不仅当前版本的查莉雅包含于我们假设的最优解(之前的版本),她还可以做到给两个队友套盾或者连续给自己套两个盾,也就证明了现在版本的查莉雅至少不会比我们假设为更优的之前版本的查莉雅更差,这就体现了一种包含关系。
如何理解第三条呢,很简单,对于我们套出的每一个盾,新版都能做到和老版一样,并且还可以做出更灵活的操作,这就是“如果我们可以最优的解决子问题,我们可以将子问题的解和贪心选择得到原问题的解”
至于第二条嘛。。反正我没有看懂。
来个例子 P3942 将军令
题意就不赘述了,在这个题里面我们采用每次找深度最深的点的第
三角形表示一棵很大的子树,图中深度关系已大致体现
这时我们取出最深的
假设我们往上找
每次找到一个点,往他的周围暴力扩展
点击查看代码
#include<bits/stdc++.h> using namespace std; const int maxn=1e6; template <typename T>inline void re(T &x) { x=0; int f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-f; for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48); x*=f; return; } int n,k,t,cnt; struct Edge{int u,v,nex;}E[maxn]; int tote,head[maxn]; void add(int u,int v) { E[++tote].u=u,E[tote].v=v; E[tote].nex=head[u],head[u]=tote; } int fa[maxn]; int dep[maxn],vis[maxn]; struct node{int x,dep;}; bool operator <(node a,node b){return a.dep<b.dep;} priority_queue<node> q; void dfsbasic(int x) { for(int i=head[x];i;i=E[i].nex) { int v=E[i].v; if(dep[v]) continue; fa[v]=x;dep[v]=dep[x]+1; dfsbasic(v); } q.push((node){x,dep[x]}); } int f(int x){for(register int i=1;i<=k;++i){x=fa[x];if(x==1)return 1;}return x;} void dfsupd(int x,int fa,int com)/*x,x,0*/ { if(com==k+1)return ; if(!vis[x])vis[x]=1,cnt++; for(register int i=head[x];i;i=E[i].nex) { int v=E[i].v; if(v==fa)continue; dfsupd(v,x,com+1); } } int main() { re(n),re(k),re(t); int u,v; for(register int i=1;i<n;++i) { re(u),re(v); add(u,v),add(v,u); } int rep=1; dep[rep]=1,fa[rep]=rep,dfsbasic(rep); int pick=0; while(!q.empty()) { node tmp=q.top();q.pop(); int x=tmp.x; if(vis[x])continue; int sfa=f(x); dfsupd(sfa,sfa,0); pick++; if(cnt==n)break; } printf("%d",pick); return 0; }
本文来自博客园,作者:Hanggoash,转载请注明原文链接:https://www.cnblogs.com/Hanggoash/p/16770405.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效