当前位置: 首页 > news >正文

P1668 [USACO04DEC] Cleaning Shifts S 题解

P1668 [USACO04DEC] Cleaning Shifts S 题解

题目传送门

我的博客

前言

这道题有 \(3\) 种方法。本文将依次进行讲解。

做法 \(1\):贪心。笔者一开始的思路就是这个。

做法 \(2\):最短路。很巧妙的方法。

做法 \(3\):DP。

做法一:贪心

首先我们按照每个区间的左端点进行排序。这样方便我们后面贪心。假设 \(d\) 为当前需要覆盖的时间。我们每次要贪心的找能覆盖 \(d\) 的右端点最靠右的一个区间,统计到答案里。如果 \(d\) 不能被任一区间覆盖,则无解。

时间复杂度 \(O(N)\)

代码

const int N=3e4+10;
int n,m,ans;
bool fl;
struct node{int l,r;
}a[N];
bool cmp(node A,node B){return A.l<B.l;//按照左端点排序,保证最优
}
signed main(){n=Read();m=Read();for(int i=1;i<=n;i++){a[i].l=Read(),a[i].r=Read();}sort(a+1,a+n+1,cmp);int d=1,rr=0;//d:当前位置,rr:最远的 rfor(int i=1;i<=n;i++){int j=i-1;rr=0;while(j<=n&&a[j].l<=d) {//贪心找右端点最靠右的点rr=max(rr,a[j].r);j++;}i=j-1;		if(rr<d) break;//d 无法被覆盖到ans++;d=rr+1;		if(rr>=m){printf("%lld\n",ans);return 0;}}puts("-1");return 0; 
}

做法二:最短路

这个方法十分巧妙。看题解之前,笔者还在纳闷为甚标签里面有“最短路”。
思路借鉴这篇题解的思路。

我们建出如下图所示的图。

\(t+1\)\(1\) 的这一条链,可以理解为每个时间均可以被覆盖,不是仅仅只能有且仅有一个奶牛在值班。额外的几个中转点,可以理解为在 \([l,r+1]\) 上有一个方案,如果要更新到 \(t+1\) 的话必然要走这些方案。

最终的答案即为 \(1\)\(t+1\) 的最短路。

时间复杂度 \(O(n \log n)\)

代码

const int N=3e4+10,M=1e6+10;
int n,m,ans;
struct edge{int nxt,to,w;
}e[M*2+N+M];//嗯对算清楚,别开小,实在不行直接 M<<2
int head[N+M],num_Edge=0;
void add_Edge(int from,int to,int w){e[++num_Edge].nxt=head[from];e[num_Edge].to=to;e[num_Edge].w=w;head[from]=num_Edge;
}
int dis[N+M];
bool vis[N+M];//数组!!不要开小!!
struct node{int id,w;bool operator < (const node &A)const {return w>A.w;}
};
priority_queue<node> q;
void dij(int s){//dijktra 板子for(int i=1;i<=n+m+1;i++) dis[i]=INF;//注意范围for(int i=1;i<=n+m+1;i++) vis[i]=0;dis[s]=0;q.push((node){s,0});while(!q.empty()){int u=q.top().id;q.pop();if(vis[u]) continue;vis[u]=1;for(int i=head[u];i;i=e[i].nxt){int v=e[i].to;if(dis[v]>dis[u]+e[i].w){dis[v]=dis[u]+e[i].w;q.push((node){v,dis[v]}); }}} 
}
signed main(){n=Read();m=Read();for(int i=m+1;i>=2;i--){add_Edge(i,i-1,0);}for(int i=1;i<=n;i++){int l=Read(),r=Read();add_Edge(l,m+i+1,1);add_Edge(m+i+1,r+1,0);}dij(1);if(dis[m+1]>=INF) puts("-1");else printf("%lld\n",dis[m+1]);return 0; 
}

做法三:线段树优化DP

考虑 \(n^3\) 的朴素DP。

...
for(int i=l;i<=r;i++){for(int j=l;j<=r;j++){dp[i][j]=0;}
}
...
for(int o=1;o<=t;o++)for(int i=1;i+o-1<=t;i++){int j=i+o-1;for(int k=i;k<j;k++)dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);}

尝试优化。可以把DP变成线性DP。

\(dp_i\) 表示 \([1,i]\) 内需要用的奶牛的数量。
如果一个奶牛 \(l=1\),则 \(dp_r=1\)
否则转移 \(dp_r=\min \{dp_j\}\)
需要注意的是,要按照 \(r\) 从小到大排序。

时间复杂度 \(O(nt)\)

我们又注意到每次需要求一个区间内的最小值,因此想到可以用线段树进行优化,让时间复杂度降 \(O(n \log t)\)

代码

const int N=3e4+10,M=1e6+10;
int n,m;
struct node{int l,r;
}a[N];
bool cmp(node A,node B){return A.r<B.r;
}
//线段树板子,只需要维护区间最小值
struct tree{int l,r,mn;
}tr[M<<2];
#define ls (root<<1)
#define rs ((root<<1)|1)
void pushup(int root){tr[root].mn=min(tr[ls].mn,tr[rs].mn);
}
void built(int root,int l,int r){if(l==r){tr[root]=(tree){l,r,INF};return ;}tr[root]=(tree){l,r,INF};int mid=(l+r)>>1;built(ls,l,mid);built(rs,mid+1,r);pushup(root);
}
void change(int root,int pos,int v){//单点修改if(tr[root].l==pos&&tr[root].r==pos){tr[root].mn=v;return ;}int mid=(tr[root].l+tr[root].r)>>1;if(pos<=mid) change(ls,pos,v);else change(rs,pos,v);pushup(root); 
}
int query(int root,int from,int to){//区间查询if(from<=tr[root].l&&to>=tr[root].r){return tr[root].mn;}int mid=(tr[root].l+tr[root].r)>>1;int res=INF;if(from<=mid) res=min(res,query(ls,from,to));if(to>mid) res=min(res,query(rs,from,to));return res;
}
//以上线段树
signed main(){n=Read();m=Read();built(1,1,m);	for(int i=1;i<=n;i++){int l=Read(),r=Read();a[i]=(node){l,r};if(l==1) change(1,r,1);//初状态}sort(a+1,a+n+1,cmp);//按照右端点排序for(int i=1;i<=n;i++){int t=min(query(1,a[i].r,a[i].r),query(1,a[i].l-1,a[i].r-1)+1);change(1,a[i].r,t);}int t=query(1,m,m);if(t>=INF) puts("-1");else printf("%lld\n",t);return 0; 
}

警示后人

  • 数组一定要算清楚开多少,不要开小!!!
http://www.zskr.cn/news/41139.html

相关文章:

  • 关于浏览器访问http://协议自动跳转至https://的处理
  • 天气预报--查看相应
  • LIN总线-帧的结构
  • 汉字识别代码
  • 如何选择适合的海外外呼系统电销服务商?
  • 循环队列通用模版
  • 如何选择一个人工智能项目
  • STL初识project11
  • CSS 中 overflow 属性的两个分属性 overflow-x 和 overflow-y 互相影响问题
  • Day13显示模式
  • 如何是一个人工智能公司
  • 关于OpenGL在AMD设备无法显示内容的解决方法
  • 超越代码补全:5个能理解你项目上下文的AI编程伙伴
  • 共绩算力 vscode git笔记
  • 不止高精度!正点原子 EL15 深度解析:精度、性价比全拉满!
  • NOIP 模拟赛 2 总结
  • 利用点击劫持漏洞触发XSS攻击:我是如何赚取350美元的
  • 人狗大战Ⅳ
  • 2025年智能家居产品品牌推荐排行 top 5
  • Web3 去魅:写给程序员和普通人的技术解读
  • 2025年度全自动四辊卷板机制造商推荐:四辊卷板机哪家好
  • 2025 年安全触边厂家最新推荐榜:聚焦品质服务商,结合权威测评与市场口碑的全面选购指南防爆灵敏安全触边/无人车安全触边公司推荐
  • 2025 年 11 月高性价比学习机推荐:松鼠 AI S20 深度测评与选购指南
  • 什么是未来的好产业
  • 安川机器人管材焊接智能节气仪
  • 2025年无线充电方案厂家新排行榜,稳定无线充电方案公司推荐
  • 2025年升降舞台机械厂家权威推荐榜单:移动舞台机械/舞台机械方案/异形舞台机械源头厂家精选
  • 2025年河北公司注册代理记账服务权威推荐榜单:河北税务咨询/河北会计税务服务商/河北营业执照年检服务精选
  • 为运动注入智能:结合 AI、立体视觉与边缘计算
  • 2025 年 11 月电能质量分析仪厂家权威推荐榜:A类/B类/动态/三相电能质量监测仪、在线监测装置及系统精选