POJ 1201 Intervals

9 篇文章 0 订阅
2 篇文章 0 订阅
Intervals
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 27948 Accepted: 10763

Description

You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. 
Write a program that: 
reads the number of intervals, their end points and integers c1, ..., cn from the standard input, 
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n, 
writes the answer to the standard output. 

Input

The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.

Output

The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.

Sample Input

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6

Source



考前没几天啦,个人感觉差分约束这类题目还不怎么会那就做几题喽~(条件原因只能写P啦qwq)

题意:一个整数集合Z中有n个区间,每个区间[ai,bi]中至少要有ci个元素,求满足这n个约束的集合最少要有多少个数。


题解:这个很显然啊。我们可以得到这样几个式子:

0<=s[i]-s[i-1]<=1

s[bi]-s[ai-1]>=ci

把符号都转化成大于等于吧,那就变成:

s[i]-s[i-1]>=0

s[i-1]-s[i]>=-1

s[bi]-s[ai-1]>=ci

所以i-1到i建一条权值为0的边,i到i-1建一条权值为-1的边,ai-1到bi建一条权值为ci的边。

然后跑spfa即可la~

附上好丑好丑的代码qwq

pascal变量重名有多难受喔...




var n,min,max,cnt,i,h,t,e,v,u:longint;
    dis,vet,next,len,head,vis,a,b,c:array[0..1000000]of longint;
    q:array[0..10000000]of longint;
procedure add_edge(u,v,w:longint);
begin
   inc(cnt);
   vet[cnt]:=v;
   next[cnt]:=head[u];
   len[cnt]:=w;
   head[u]:=cnt;
end;
procedure spfa;
begin
   for i:=0 to max do dis[i]:=-1000000000;
   dis[min]:=0;q[1]:=min;h:=0;t:=1;vis[min]:=1;
   while h<t do
   begin
      inc(h);
      u:=q[h];
      e:=head[u];
      while e<>-1 do
      begin
         v:=vet[e];
         if dis[v]<dis[u]+len[e] then
         begin
            dis[v]:=dis[u]+len[e];
            if vis[v]=0 then
            begin
               inc(t);q[t]:=v;
               vis[v]:=1;
            end;
         end;
         e:=next[e];
      end;
      vis[u]:=0;
   end;
end;
begin
   readln(n);
   min:=1000000000;max:=-1000000000;
   fillchar(head,sizeof(head),255);
   for i:=1 to n do
   begin
      readln(a[i],b[i],c[i]);
      if a[i]-1<min then min:=a[i]-1;
      if b[i]>max then max:=b[i];
   end;
   for i:=1 to n do add_edge(a[i]-1,b[i],c[i]);
   for i:=min to max do
   begin
      add_edge(i-1,i,0);
      add_edge(i,i-1,-1);
   end;
   spfa();
   writeln(dis[max]);
end.


备注一下,上面的方法是转化为大于等于跑最长路的方法(个人较为习惯),下面贴小于等于跑最短路的代码吧,避免误解,两种方法都是可以的啦~



var n,min,max,cnt,i,h,t,e,v,u:longint;
    dis,vet,next,len,head,vis,a,b,c:array[0..1000000]of longint;
    q:array[0..10000000]of longint;
procedure add_edge(u,v,w:longint);
begin
   inc(cnt);
   vet[cnt]:=v;
   next[cnt]:=head[u];
   len[cnt]:=w;
   head[u]:=cnt;
end;
procedure spfa;
begin
   for i:=min to max do dis[i]:=1000000000;
   dis[max]:=0;q[1]:=max;h:=0;t:=1;vis[max]:=1;
   while h<t do
   begin
      inc(h);
      u:=q[h];
      e:=head[u];
      while e<>-1 do
      begin
         v:=vet[e];
         if dis[v]>dis[u]+len[e] then
         begin
            dis[v]:=dis[u]+len[e];
            if vis[v]=0 then
            begin
               inc(t);q[t]:=v;
               vis[v]:=1;
            end;
         end;
         e:=next[e];
      end;
      vis[u]:=0;
   end;
end;
begin
   readln(n);
   min:=1000000000;max:=-1000000000;
   fillchar(head,sizeof(head),255);
   for i:=1 to n do
   begin
      readln(a[i],b[i],c[i]);
      if a[i]<min then min:=a[i];
      if b[i]+1>max then max:=b[i]+1;
   end;
   for i:=1 to n do add_edge(b[i]+1,a[i],-c[i]);
   for i:=min to max-1 do
   begin
      add_edge(i+1,i,0);
      add_edge(i,i+1,1);
   end;
   spfa();
   writeln(-dis[min]);
end.







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值