笨笨种西瓜(差分约束)题解


P1385笨笨种西瓜
限制 : 时间限制 : 10000 MS   空间限制 : 165536 KB
问题描述

笨笨种了一块西瓜地,但这块西瓜地的种植范围是一条直线的……
笨笨在一番研究过后,得出了m个结论,这m个结论可以使他收获的西瓜最多。
笨笨的结论是这样的:
从西瓜地B处到E处至少要种植T个西瓜,这个范围的收获就可以最大化。
笨笨不想那么辛苦,所以他想种植的西瓜尽量少,而又满足每一个所得的结论。

输入格式

第一行两个数n,m(0<n<=5000,0<=m<=3000),表示笨笨的西瓜地长n,笨笨得出m个结论。
接下来m行表示笨笨的m个结论,每行三个数b,e,t(1<=b<=e<=n,0<=t<=e-b+1)。

输出格式

输出笨笨最少需种植多少西瓜。

样例输入

9 4
1 4 2
4 6 2
8 9 2
3 5 2

样例输出

5

提示

基本上来说,笨笨的西瓜地就是一条壮观的线……
【题解】

1、思路:需要满足众多不等式,of course 差分约束。

2、具体;

(1)一条线>>前缀和数组dis;

(2)满足dis[i]-dis[i-1]<=1(每个地方只能种一个);

(3)满足dis[i]-dis[i-1]>=0(肯定不能小于零);

(4)满足dis[e]-dis[b-1]>=t(题意);

(5)加虚拟源点跑最长路吧,少年!!!!!

【代码】

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int inf=999999999;
int n,m,dis[5005],st;
bool f[5005];
queue<int>q;
int tot=0,lastt[5005],endd[15005],len[15005],nextt[15005];
void addd(int x,int y,int z)
{
 tot++;
 endd[tot]=y;
 len[tot]=z;
 nextt[tot]=lastt[x];
 lastt[x]=tot;
}
void spfa(int s)
{
 int i,x,t,y,l;
 for(i=0;i<=n;i++)
 dis[i]=-inf,f[i]=false;
 while(!q.empty())q.pop(); 
 dis[s]=0,f[s]=true,q.push(s);
 while(!q.empty())
 {
  x=q.front();
  f[x]=false;
  q.pop();
  t=lastt[x];
  while(t)
  {
   y=endd[t];
   if(dis[y]<dis[x]+len[t])
   {
    dis[y]=dis[x]+len[t];
    if(!f[y])
    {
     q.push(y);
     f[y]=true;
    }
   }
   t=nextt[t];
  }
 }
}
int main()
{
 scanf("%d%d",&n,&m);
 st=n+1;
 int i,b,e,t;
 for(i=1;i<=m;i++)
 {
  scanf("%d%d%d",&b,&e,&t);
  addd(b-1,e,t);
 }
 for(i=1;i<=n;i++)
 addd(i,i-1,-1),addd(st,i,0),addd(i-1,i,0);
 addd(st,0,0);
 spfa(st);
 printf("%d\n",dis[n]);
 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值