zoukankan      html  css  js  c++  java
  • Intervals(差分约束)

    http://poj.org/problem?id=1201

    题意:给出N个整数区间[ai,bi],并且给出一个约束ci,( 1<= ci <= bi-ai+1),使得数组Z在区间[ai,bj]的个数>= ci个,求出数组Z的最小长度。

    思路:建立差分约束系统。因为这里要求数组长度的最小值,要变为 x-y>=k的标准形式。

    设数组 s[j] 表示数组 Z 区间[0,j]里包含的元素个数。所以 s[bi+1] - s[ai] >= ci,注意是 j+1,

    隐含条件   0 <= s[i+1]-s[i] <= 1;

    故差分约束系统为:

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

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

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

    然后邻接表建图求最长路。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<stack>
     5 using namespace std;
     6 
     7 const int maxn = 500100;
     8 const int INF = 0x3f3f3f3f;
     9 struct node
    10 {
    11     int u,v,w;
    12     int next;
    13 }edge[maxn];
    14 
    15 int n,p[maxn],cnt;
    16 int Min,Max;
    17 int dis[maxn],instack[maxn],vexcnt[maxn];
    18 
    19 void add(int u, int v, int w)
    20 {
    21     cnt++;
    22     edge[cnt].u = u;
    23     edge[cnt].v = v;
    24     edge[cnt].w = w;
    25     edge[cnt].next = p[u];
    26     p[u] = cnt;
    27 }
    28 
    29 bool SPFA()
    30 {
    31     stack<int>st;
    32     while(!st.empty()) st.pop();
    33     memset(instack,0,sizeof(instack));
    34     memset(vexcnt,0,sizeof(vexcnt));
    35     for(int i = Min; i <= Max; i++)
    36         dis[i] = -INF;
    37 
    38     st.push(Min);
    39     dis[Min] = 0;
    40     instack[Min] = 1;
    41     vexcnt[Min]++;
    42 
    43     while(!st.empty())
    44     {
    45         int u = st.top();
    46         st.pop();
    47         instack[u] = 0;
    48 
    49         for(int i = p[u]; i; i = edge[i].next)
    50         {
    51             if(dis[edge[i].v] < dis[u] + edge[i].w)
    52             {
    53                 dis[edge[i].v] = dis[u] + edge[i].w;
    54                 if(!instack[edge[i].v])
    55                 {
    56                     instack[edge[i].v] = 1;
    57                     st.push(edge[i].v);
    58                     vexcnt[edge[i].v]++;
    59                     if(vexcnt[edge[i].v] > n)
    60                         return false;
    61                 }
    62             }
    63         }
    64     }
    65     return true;
    66 }
    67 
    68 int main()
    69 {
    70     int u,v,w;
    71     scanf("%d",&n);
    72 
    73     cnt = 0;
    74     memset(p,0,sizeof(p));
    75     Min = INF,Max = -1;
    76 
    77     for(int i = 0; i < n; i++)
    78     {
    79         scanf("%d %d %d",&u,&v,&w);
    80         add(u,v+1,w);
    81         Min = min(Min,u);
    82         Max = max(Max,v+1);
    83     }
    84     for(int i = Min; i < Max; i++)
    85     {
    86         add(i,i+1,0);
    87         add(i+1,i,-1);
    88     }
    89     SPFA();
    90     printf("%d
    ",dis[Max]-dis[Min]);
    91     return 0;
    92 }
    View Code

    关于差分约束:

    比如给出三个不等式,b-a<=k1,c-b<=k2,c-a<=k3,求出c-a的最大值,我们可以把a,b,c转换成三个点,k1,k2,k3是边上的权,如图

    由题我们可以得知,这个有向图中,由题b-a<=k1,c-b<=k2,得出c-a<=k1+k2,因此比较k1+k2和k3的大小,求出最小的就是c-a的最大值了

    根据以上的解法,我们可能会猜到求解过程实际就是求从a到c的最短路径,没错的....简单的说就是从a到c沿着某条路径后把所有权值和k求出就是c -a<=k的一个

    推广的不等式约束,既然这样,满足题目的肯定是最小的k,也就是从a到c最短距离...

    理解了这里之后,想做题还是比较有困难的,因为题目需要变形一下,不能单纯的算..

    首先以poj3159为例,这个比较简单,就是给出两个点的最大差,然后让你求1到n的最大差,直接建图后用bellman或者spfa求最短路就可以过了

    稍微难点的就是poj1364,因为他给出的不等式不是x-y<=k形式,有时候是大于号,这样需要我们去变形一下,并且给出的还是>,<没有等于,都要变形

    再有就是poj1201,他要求出的是最长距离,那就要把形式变换成x-y>=k的标准形式

    注意点:

    1. 如果要求最大值想办法把每个不等式变为标准x-y<=k的形式,然后建立一条从y到x权值为k的边,变得时候注意x-y<k =>x-y<=k-1

       如果要求最小值的话,变为x-y>=k的标准形式,然后建立一条从y到x的k边,求出最长路径即可

    2.如果权值为正,用dj,spfa,bellman都可以,如果为负不能用dj,并且需要判断是否有负环,有的话就不存在

  • 相关阅读:
    指针常量 和 常量指针
    串口通讯
    C语言的抽象与函数指针2
    STM32 中常见错误 的处理方法
    串行通信之狂扯篇
    VMware中虚拟机网卡的四种模式
    VSFTP配置虚拟用户
    MySQL数据库备份命令
    rsync Linux系统下的数据镜像备份工具
    linux常用命令
  • 原文地址:https://www.cnblogs.com/LK1994/p/3440362.html
Copyright © 2011-2022 走看看