[POJ 1201] Intervals 差分约束系统

题目传送门:【POJ 1201】


题目大意:给定一个长度为 n 的序列(1 ≤ n ≤ 50000),序列中所有数字都为非负数且不相同。
题目将会以一些三元组 [a,b,c] 对这个数列进行描述,表示第 i 个序列中数值在 [a i ,b i ] 之间的数字至少有 c i 个。
询问使得所有条件都成立的序列长度最短是多少。(0 ≤ ai ≤ bi ≤ 50000,1 ≤ ci ≤ bi - ai + 1)
注意,输入中仅包含 n 和之后 n 个区间的信息。


题目分析:

这道题有很多种做法。不过对于差分约束系统来说,应该是一道裸题了。

我们设 S i 表示 0-i 中必须要选的数的个数;那么,根据题目信息,我们可以将所有的三元组 [a i , b i , c i ] 转化为一系列的不等式:S bi - S ai1 ≥ c i 。然后,对于这样的不等式,我们对所有的 a i -1 号点到 b i 号点连一条权值为 c i 的单向边。

题目中还有两个隐含条件:S i1 ≤ S i ≤ S i1 +1;对于这样的条件,我们对 i-1 号点到 i 号点连一条权值为 0 的单向边,然后从 i 号点到 i-1 号点连一条权值为 -1 的边(这样可以保证不会走成一个环,同时也可以绕回去)。然后,跑一遍最长路即可。

至于要怎么跑最长路……其实把 dis 数组初始化为一个很小的数,然后判断条件改成 dis[u] + len > dis[v] 就行辣

下面附上代码:

  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<algorithm>  
  4. #include<queue>  
  5. using namespace std;  
  6. typedef long long LL;  
  7. const int MX=50005;  
  8.   
  9. struct Edge{  
  10.     int to,len,next;  
  11. }edge[MX*4];  
  12. int n,m,head[MX],now=0,dis[MX],cnt=0;  
  13. bool inq[MX];  
  14. queue<int> q;  
  15.   
  16. inline void adde(int u,int v,int len){  
  17.     edge[++now].to=v;  
  18.     edge[now].len=len;  
  19.     edge[now].next=head[u];  
  20.     head[u]=now;  
  21. }  
  22. void bfs(int s){  
  23.     q.push(s);  
  24.     dis[s]=0;  
  25.     inq[s]=true;  
  26.     while (!q.empty()){  
  27.         int u=q.front();  
  28.         q.pop();  
  29.         inq[u]=false;  
  30.         for (int i=head[u];i;i=edge[i].next){  
  31.             int v=edge[i].to;  
  32.             if (dis[u]+edge[i].len>dis[v]){                          //求最长路   
  33.                 dis[v]=dis[u]+edge[i].len;  
  34.                 if (!inq[v]){  
  35.                     inq[v]=true;  
  36.                     q.push(v);  
  37.                 }  
  38.             }  
  39.         }  
  40.     }  
  41. }  
  42.   
  43. int main(){  
  44.     memset(dis,0x9f,sizeof(dis));  
  45.     int a,b,v;  
  46.     scanf(”%d”,&m);  
  47.     for (int i=1;i<=m;i++){  
  48.         scanf(”%d%d%d”,&a,&b,&v);                       //这里的处理(b++)使得起始点变为 1,防止溢出   
  49.         b++;  
  50.         adde(a,b,v);  
  51.     }  
  52.     for (int i=1;i<=50000;i++){                          //区间覆盖的最大值为 50000,所以只需要建到 50000   
  53.         adde(i,i+1,0);  
  54.         adde(i+1,i,(-1));  
  55.     }  
  56.     bfs(1);  
  57.     printf(”%d”,dis[50001]);  
  58.     return 0;  
  59. }  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值