luogu P1250 种树
Posted xmex
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P1250 种树相关的知识,希望对你有一定的参考价值。
我来总结一下最常用的两种办法
1.贪心
2.差分约束
那么我们先来讲,贪心版《种树》
大家可能知道有一个题和这个类似,那个是钉钉子而这个是种树
我们可以借用钉钉子的思路来想,首先这个是让你求最小值,而且每个人都有自己划定的区间,并且他们还要求在这段区间内最少种T棵树。
那么我们既要满足最少种树数,而且要满足每个人的要求。好在的是,题目中说过区间和区间之间可能会有一段重叠,那么我们要抓住这个机会尽可能多的在每一段重复区间内多种树,所以就会产生一个连锁反应,就是上一个重复区间内种的树可能会满足下一个人的要求,那么这个人就可以略过去,以达到最少数的目的。
(以下是贪心代码,体会一下)
#include<bits/stdc++.h> using namespace std; const int N = 31000; int n,m,ans=0; bool u[N]={0}; struct Edge{ int x,y,z; }a[N]; bool cmp(Edge a,Edge b) { return a.y<b.y; } int main() { cin>>n>>m; for(int i=1;i<=m;i++) cin>>a[i].x>>a[i].y>>a[i].z; sort(a+1,a+m+1,cmp); for(int i=1;i<=m;i++) { int sum=0; for(int j=a[i].x;j<=a[i].y;j++) if(u[j]) sum++;//统计已有的数量 if(sum>=a[i].z) continue;//满足就继续 for(int k=a[i].y;k>=a[i].x;k--)//不满足情况 { if(!u[k]) { u[k]=1; sum++; ans++;//答案++ if(sum==a[i].z) break;//直到满足,退出 } } } cout<<ans;//输出最后答案(即最少的树的数量) return 0; }
接下来我们讲,差分约束版《种树》
我们都知道差分约束是用于最短路不等式问题的
这里我们利用差分约束解决最短路不等式的性质来看
我们想在区间内种最少的树,所以根据性质
我们可以列出两个差分约束公式
1.sum[x]-sum[y-1]>=c;(这里是指在区间[y,x]中至少种c棵树)
2.0<=sum[x]-sum[x-1]<=1;(这里是指一个单位长度内最多种1棵树)
根据公式,我们可以建边,但是建边是y+1->y=-1而不是y->y+1=1
建好边我们就可以跑一边SPFA啦,最少种树数也就出来了!
(差分约束代码,体会一下)
#include<bits/stdc++.h> using namespace std; const int N = 31000; const int M = 110000; int n,m; int dis[N]; bool vis[N]; int head[N],num; struct Edge{ int to,next,w; }s[M]; void add(int u,int v,int w)//根据公式建边 { s[++num].w=w; s[num].next=head[u]; head[u]=num; s[num].to=v; } void spfa(int x)//SPFA经典操(ban)作(zi) { queue<int> q; q.push(x); for(int i=0;i<=n+1;i++) dis[i]=1; dis[x]=0;vis[x]=1; while(!q.empty()) { int g=q.front(); q.pop(); vis[g]=0; for(int i=head[g];i!=-1;i=s[i].next) { int t=s[i].to; if(dis[t]>dis[g]+s[i].w) { dis[t]=dis[g]+s[i].w; if(!vis[t]) { q.push(t); vis[t]=1; } } } } } int main() { int a,b,c,minn=123456789; memset(head,-1,sizeof(head)); cin>>n>>m; int y=n+1; for(int i=0;i<=n;i++) add(y,i,0); for(int i=1;i<=m;i++) { cin>>a>>b>>c; add(b,a-1,-c); } for(int i=1;i<=n;i++)//建边操作 { add(i-1,i,1); add(i,i-1,0); } spfa(y); for(int i=0;i<=n;i++)//取最小值 minn=min(minn,dis[i]); cout<<dis[n]-minn<<endl; return 0; }
烟雨江南,无你何欢!
以上是关于luogu P1250 种树的主要内容,如果未能解决你的问题,请参考以下文章