题目描述

一条街的一边有几座房子。因为环保原因居民想要在路边种些树。路边的地区被分割成块,并被编号成1…N。每个部分为一个单位尺寸大小并最多可种一棵树。每个居民想在门前种些树并指定了三个号码B,E,T。这三个数表示该居民想在B和E之间最少种T棵树。当然,B≤E,居民必须记住在指定区不能种多于区域地块数的树,所以T≤E-B+l。居民们想种树的各自区域可以交叉。你的任务是求出能满足所有要求的最少的树的数量。

写一个程序完成以下工作:

输入格式 第一行包含数据N,区域的个数(0<N≤30000);

第二行包含H,房子的数目(0<H≤5000);

下面的H行描述居民们的需要:B E T,0<B≤E≤30000,T≤E-B+1。

输出格式 输出文件只有一行写有树的数目

输入输出样例

输入 #1 复制
9
4
1 4 2
4 6 2
8 9 2
3 5 2
输出 #1 复制
5

思路(差分约束)

其实本题没有什么要多想的,就一些东西要注意:

  1. 首先本题让求的是 “最小种树数量”,既然是最小那么我们就要 我们就要 用 Spfa 跑 “最长路径”(具体为啥可以参考我的理解)。
  2. 把所给的(隐藏的和直接给出来的)不等式全部变 “ >= ” 的形式
  3. 找出题目上给的(包括题目中隐藏的约束 不等式条件找出来)
    • 对于输入的不等式条件: 假定为: u, v, w ;那么我们可以列出不等式:v - (u-1) >= w,那么我们直接建边 (u - 1) -> v 其权值为 w
    • 对于题意中(每个部分为一个单位尺寸大小并最多可种一棵树)的不等式:对于任意一个距离点:u 我们考虑: 0 <= u - (u-1)<= 1,我可以把它变成两个不等式: u - (u-1) >=0 、u - (u-1) <= 1 , 将他们变成 “ >= ”的形式为:u = (u-1) + 0(u-1) >= u - 1,因此对于一个 点u我们可以建了两条边:(u-1) -> u 权值为 0u ->(u-1) 权值为 -1…//////////////最后 u的取值范围为 1~n, 所以一次便利所有可能的u,把边都建立上就行了
    • 最后别忘了,考虑一下“超级源点”在这一题中为 0。。。。。。

最后贴出 luogu 大佬的思路

题解

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 300005;
const int maxm = 300000;
int m,n;
struct Edge
{
int v,w,next;
} edge[maxm];
int head[maxn], dis[maxn];
int k = 0; void Add(int u, int v, int w)
{
edge[++ k] = (Edge){ v, w, head[u]}; head[u] = k;
} int Spfa(int s, int e)
{
int use[maxn] = {0};
queue<int> q;
q.push(s);
int u,v,w;
while(! q.empty())
{
u = q.front(); q.pop();
use[u] = 0; for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
w = edge[i].w;
if(dis[v] < dis[u] + w)
{
dis[v] = dis[u] + w;
if(! use[v])
{
q.push(v);
use[v] = 1;
}
}
}
}
return dis[n];
} void init()
{
k = 0;
for(int i = 0; i <= n; i ++)
head[i] = -1, dis[i] = -INF;
dis[0] = 0;
} int main()
{
ios::sync_with_stdio(false); cin.tie(0);
//freopen("T.txt","r",stdin);
cin >> n >> m;
init();
int u,v,w;
for(int i = 1; i <= m; i ++)
{
cin >> u >> v >> w;
// v - u >= w
Add(u-1, v, w);
}
for(int i = 1; i <= n; i ++)
{
Add(i-1, i, 0);
Add(i, i-1,-1);
// a - b >= 0 a >= b
// a - b <= 1 b >= a - 1
} cout << Spfa(0, n) << endl; return 0;
}

思路(贪心)

这题可以用 贪心 的思想去考虑这个问题,这里可以部分借鉴:“贪心 区间选点问题”的一下思路,,,,我们可以题目所给的区间(u,v)按 结束位置v从 小到大 排序,如果两个区间结束位置相同,那么按照 区间开始的位置u 从大 到小排序,,,排序完之后,我们考虑 要想种植最少的树,那么 一棵树就要尽可能多的被多个的区间利用, 而在该区间种树的位置,越靠近区间后面的位置有越大的概率,被下一区间重复利用,而我需要的就是这个重复利用,所以我们在选择中树的时候,应该从后往前植树, 对于第一区间, 它需要多少棵树就从后往前种多少棵树(其实是做标记),对于以后的区间,缺树我们就中树,不缺就继续遍历下一个空间。。。。

具体步骤

  1. 对区间排序
  2. 对每个区间依次处理

    1.从前往后在当前区间中已经有的树(标记)的数量

    2.若树(标记)的数量小于要当前区间要求种植的数量,从后往前种植树(做标记)
 3.输入ans

题解

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxm = 30005;
int n,m; struct Edge
{
int u,v,w;
bool operator <(const Edge& a) const
{
if(v == a.v)
return u > a.u;
return v < a.v;
}
} edge[maxm]; int area[maxm]; int main()
{
ios::sync_with_stdio(false); cin.tie(0);
//freopen("T.txt","r",stdin);
cin >> n >> m;
for(int i = 0; i < m; i ++)
cin >> edge[i].u >> edge[i].v >> edge[i].w;
sort(edge, edge + m);
int u,v,w;
int ans = 0;
for(int i = 0; i < m; i ++)
{
int cnt = 0;
u = edge[i].u; v = edge[i].v; w = edge[i].w;
//cnt统计已有的标记的个数
for(int j = u; j <= v; j ++) if(area[j]) cnt ++;
//在区域的尾部添加数
for(int j = v; j >= u; j --)
{
if(cnt >= w)
break;
if(! area[j])
{
area[j] = 1;
cnt ++;
ans ++;
}
}
}
cout << ans << endl; return 0;
}

P1250 种树(差分约束 / 贪心)的更多相关文章

  1. 种树-洛谷P1250(差分约束)

    传送门 令前缀和为s[i],则⼀一个要求等价于 s[r] - s[l - 1] >= x. 题中还有别的要求,包括 s[i] - s[i - 1] <= 1 和 s[i] - s[i- 1 ...

  2. 题解——洛谷P1250 种树(差分约束)

    一道看一眼就知道差分约束的题目 但是最短路spfa的时候注意松弛条件是 if(dis[u]+w[i]<dis[v[i]]) dis[v[i]]=dis[u]+w[i]; 不能写成 if(dis[ ...

  3. 【最短路·差分约束】洛谷P1250

    题目描述 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号成1..N.每个部分为一个单位尺寸大小并最多可种一棵树.每个居民想在门前种些树并指定了三个号码B,E, ...

  4. poj 1716 Integer Intervals (差分约束 或 贪心)

    Integer Intervals Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 12192   Accepted: 514 ...

  5. 算法复习——差分约束(ssoi种树)

    题目: 题目描述 为了绿化乡村,H 村积极响应号召,开始种树了. H 村里有 n 幢房屋,这些屋子的排列顺序很有特点,在一条直线上.于是方便起见,我们给它们标上 1-n .树就种在房子前面的空地上. ...

  6. [ZPG TEST 115] 种树【差分约束】

    4. 种树 (trees.pas/c/cpp) [问题描述] 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号为1..n.每个块的大小为一个单位尺寸并最多可种一 ...

  7. 洛谷P1250种树(贪心)

    题目描述 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号成1..N.每个部分为一个单位尺寸大小并最多可种一棵树.每个居民想在门前种些树并指定了三个号码B,E, ...

  8. Codevs 1768 种树 3(差分约束)

    1768 种树 3 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 为了绿化乡村,H村积极响应号召,开始种树了. H村里有n幢 ...

  9. P1250 种树

    P1250 种树 题目描述 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号成1..N.每个部分为一个单位尺寸大小并最多可种一棵树.每个居民想在门前种些树并指定 ...

随机推荐

  1. Spring MVC系列-(1) Spring概述

    1. Spring概述 本章主要介绍Spring中的体系结构和常见概念,比如bean.控制反转(Inverse of Control,IoC)等. 1.1 体系结构 Spring 框架提供约 20 个 ...

  2. Asp.Net Core 中IdentityServer4 授权中心之应用实战

    一.前言 查阅了大多数相关资料,查阅到的IdentityServer4 的相关文章大多是比较简单并且多是翻译官网的文档编写的,我这里在 Asp.Net Core 中IdentityServer4 的应 ...

  3. ElasticSearch 6.2.4 实践

    参考资料 ElasticSearch 官网 ElasticSearch,Kibana,Asp.net Core with docker 示例 阮一峰 ElasticSearch 基础概念 索引(ind ...

  4. php中的进程

    pcntl扩展:主要的进程扩展,完成进程创建于等待操作. posix扩展:完成posix兼容机通用api,如获取进程id,杀死进程等. sysvmsg扩展:实现system v方式的进程间通信之消息队 ...

  5. Serverless与微服务

    Serverless 是一个更大的范畴,Serverless 不只计算,也包括存储.数据库.中间件等各种服务.Serverless = FaaS(函数即服务) + BaaS(后端即服务).其中 Ser ...

  6. str的常用方法

    注:s表示定义的一个字符串变量,如:s = 'hello string' 1.  s.index()  查找元素,若查到则返回该元素索引,含多个该元素则返回第一个,查不到则报错 s = 'hello ...

  7. 测试必知必会系列- Linux常用命令 - ps(重点)

    21篇测试必备的Linux常用命令,每天敲一篇,每次敲三遍,每月一循环,全都可记住!! https://www.cnblogs.com/poloyy/category/1672457.html 查看所 ...

  8. vuepress-theme-reco + Github Actions 构建静态博客,部署到第三方服务器

    最新博客链接 Github链接 查看此文档前应先了解,vuepress基本操作 参考官方文档进行配置: vuepress-theme-reco VuePress SamKirkland / FTP-D ...

  9. Spring 全局异常拦截根据业务返回不同格式数据 自定义异常

    1.全局异常拦截:针对所有异常进行拦截 可根据请求自定义返回格式 2.自定义异常类 处理不同业务的异常 接下来开始入手代码: 1).自定义异常类 @ControllerAdvice//添加注解 记得开 ...

  10. 大数据软件安装之Flume(日志采集)

    一.安装地址 1) Flume官网地址 http://flume.apache.org/ 2)文档查看地址 http://flume.apache.org/FlumeUserGuide.html 3) ...