zoukankan      html  css  js  c++  java
  • 差分约束系统

    变量之间的不等关系转成最短/长路求解。

    若A - B <= x

    则A <= B + x,此时有一条B->A边权为x的边。

    一个形象的图:

    不要忘了问题本身的约束条件。

    求最小值->最长路

    最大值->最短路

    负环->无解

    不连通->多解

    参考资料

    例题:

    HDU1384 Intervals 注意有多组数据。

     1 #include <cstdio>
     2 #include <queue>
     3 #include <cstring>
     4 
     5 const int N = 100010, INF = 0x3f3f3f3f;
     6 
     7 struct Edge {
     8     int nex, v, len;
     9     Edge(int N = 0, int V = 0, int L = 0) {
    10         nex = N;
    11         v = V;
    12         len = L;
    13     }
    14 }edge[2000010]; int tp;
    15 
    16 std::queue<int> Q;
    17 int d[N], e[N], a[N], b[N], c[N];
    18 bool vis[N];
    19 
    20 inline void add(int x, int y, int z) {
    21     tp++;
    22     edge[tp] = Edge(e[x], y, z);
    23     e[x] = tp;
    24     return;
    25 }
    26 
    27 inline void spfa(int s) {
    28     memset(d, 0x3f, sizeof(d));
    29     vis[s] = 1;
    30     d[s] = 0;
    31     Q.push(s);
    32     while(!Q.empty()) {
    33         int x = Q.front();
    34         Q.pop();
    35         vis[x] = 0;
    36         for(int i = e[x]; i; i = edge[i].nex) {
    37             int y = edge[i].v;
    38             if(d[y] > d[x] + edge[i].len) {
    39                 d[y] = d[x] + edge[i].len;
    40                 if(!vis[y]) {
    41                     vis[y] = 1;
    42                     Q.push(y);
    43                 }
    44             }
    45         }
    46     }
    47     return;
    48 }
    49 
    50 int main() {
    51     int n, lm = 0;
    52     while(scanf("%d", &n) != EOF) {
    53         memset(e, 0, sizeof(e));
    54         tp = 0;
    55         memset(vis, 0, sizeof(vis));
    56         for(int i = 1; i <= n; i++) {
    57             scanf("%d%d%d", &a[i], &b[i], &c[i]);
    58             a[i]++; b[i]++;
    59             lm = std::max(lm, b[i]);
    60             /// sum[b[i]] - sum[a[i] - 1] >= c[i]
    61             add(a[i], b[i] + 1, -c[i]);
    62         }
    63         for(int i = 1; i <= lm; i++) {
    64             add(i, i + 1, 0);
    65             add(i + 1, i, 1);
    66         }
    67         spfa(1);
    68         printf("%d
    ", -d[lm + 1]);
    69     }
    70     return 0;
    71 }
    AC代码

    ZOJ2770 Burn the Linked Camp 一毛一样。多了一个判负环。

     1 #include <cstdio>
     2 #include <queue>
     3 #include <cstring>
     4 
     5 typedef long long LL;
     6 const int N = 100010;
     7 const LL INF = 0x3f3f3f3f3f3f3f3fll;
     8 
     9 struct Edge {
    10     int nex, v;
    11     LL len;
    12     Edge(int N = 0, int V = 0, LL L = 0) {
    13         nex = N;
    14         v = V;
    15         len = L;
    16     }
    17 }edge[2000010]; int tp;
    18 
    19 std::queue<int> Q;
    20 int e[N], a[N], b[N], c[N], m, n, cnt[N];
    21 LL d[N];
    22 bool vis[N];
    23 
    24 inline void add(int x, int y, LL z) {
    25     tp++;
    26     edge[tp] = Edge(e[x], y, z);
    27     e[x] = tp;
    28     return;
    29 }
    30 
    31 inline int spfa(int s) {
    32     memset(d, 0x3f, sizeof(d));
    33     memset(cnt, 0, sizeof(cnt));
    34     memset(vis, 0, sizeof(vis));
    35     vis[s] = 1;
    36     d[s] = 0;
    37     cnt[s] = 1;
    38     Q.push(s);
    39     while(!Q.empty()) {
    40         int x = Q.front();
    41         Q.pop();
    42         vis[x] = 0;
    43         for(int i = e[x]; i; i = edge[i].nex) {
    44             int y = edge[i].v;
    45             if(d[y] > d[x] + edge[i].len) {
    46                 d[y] = d[x] + edge[i].len;
    47                 cnt[y] = cnt[x] + 1;
    48                 if(cnt[y] > n + 1) {
    49                     return -1;
    50                 }
    51                 if(!vis[y]) {
    52                     vis[y] = 1;
    53                     Q.push(y);
    54                 }
    55             }
    56         }
    57     }
    58     return 0;
    59 }
    60 
    61 int main() {
    62     while(scanf("%d%d", &n, &m) != EOF) {
    63         memset(e, 0, sizeof(e));
    64         tp = 0;
    65         for(int i = 1; i <= n; i++) {
    66             scanf("%d", &c[i]);
    67             add(i + 1, i, c[i]);
    68             add(i, i + 1, 0);
    69         }
    70         for(int i = 1; i <= m; i++) {
    71             scanf("%d%d%d", &a[i], &b[i], &c[i]);
    72             add(a[i], b[i] + 1, -c[i]);
    73         }
    74         int t = spfa(1);
    75         if(t == -1) {
    76             printf("Bad Estimations
    ");
    77         }
    78         else {
    79             printf("%d
    ", -d[n + 1]);
    80         }
    81     }
    82     return 0;
    83 }
    AC代码

    HDU1531 King 注意可能不连通,而每个数也没有非负的限制,所以新建s向每个点连0边保证每个连通块都会被检查一遍。

     1 #include <cstdio>
     2 #include <queue>
     3 #include <cstring>
     4 
     5 typedef long long LL;
     6 const int N = 100010;
     7 const LL INF = 0x3f3f3f3f3f3f3f3fll;
     8 
     9 struct Edge {
    10     int nex, v;
    11     LL len;
    12     Edge(int N = 0, int V = 0, LL L = 0) {
    13         nex = N;
    14         v = V;
    15         len = L;
    16     }
    17 }edge[1000010]; int tp;
    18 
    19 std::queue<int> Q;
    20 int e[N], a[N], b[N], c[N], m, n, cnt[N];
    21 LL d[N];
    22 bool vis[N];
    23 
    24 inline void add(int x, int y, LL z) {
    25     tp++;
    26     edge[tp] = Edge(e[x], y, z);
    27     e[x] = tp;
    28     return;
    29 }
    30 
    31 inline int spfa(int s) {
    32     memset(d, 0x3f, sizeof(d));
    33     memset(cnt, 0, sizeof(cnt));
    34     memset(vis, 0, sizeof(vis));
    35     vis[s] = 1;
    36     d[s] = 0;
    37     cnt[s] = 1;
    38     Q.push(s);
    39     while(!Q.empty()) {
    40         int x = Q.front();
    41         Q.pop();
    42         vis[x] = 0;
    43         for(int i = e[x]; i; i = edge[i].nex) {
    44             int y = edge[i].v;
    45             if(d[y] > d[x] + edge[i].len) {
    46                 d[y] = d[x] + edge[i].len;
    47                 cnt[y] = cnt[x] + 1;
    48                 if(cnt[y] > n + 2) {
    49                     return -1;
    50                 }
    51                 if(!vis[y]) {
    52                     vis[y] = 1;
    53                     Q.push(y);
    54                 }
    55             }
    56         }
    57     }
    58     return 0;
    59 }
    60 
    61 char str[3];
    62 
    63 int main() {
    64     //printf("%d 
    ", (sizeof(edge) + sizeof(cnt) * 7) / 1048576);
    65     while(scanf("%d", &n), n) {
    66         scanf("%d", &m);
    67         memset(e, 0, sizeof(e));
    68         tp = 0;
    69         for(int i = 1; i <= m; i++) {
    70             scanf("%d%d%s%d", &a[i], &b[i], str, &c[i]);
    71             b[i] += a[i];
    72             if(str[0] == 'g') {
    73                 c[i]++;
    74                 add(b[i] + 1, a[i], -c[i]);
    75             }
    76             else {
    77                 c[i]--;
    78                 add(a[i], b[i] + 1, c[i]);
    79             }
    80         }
    81         for(int i = 1; i <= n + 1; i++) {
    82             add(n + 2, i, 0);
    83         }
    84 
    85         int t = spfa(n + 2);
    86         if(t != -1) {
    87             printf("lamentable kingdom
    ");
    88         }
    89         else {
    90             printf("successful conspiracy
    ");
    91         }
    92     }
    93     return 0;
    94 }
    AC代码

    HDU1534 Schedule Problem 之前的都是序列模型,这个直接就是点之间的关系,不需要序列上前缀和。

    每个事件的开始时间就是d。

      1 #include <cstdio>
      2 #include <queue>
      3 #include <cstring>
      4 
      5 typedef long long LL;
      6 const int N = 100010;
      7 const LL INF = 0x3f3f3f3f3f3f3f3fll;
      8 
      9 struct Edge {
     10     int nex, v;
     11     LL len;
     12     Edge(int N = 0, int V = 0, LL L = 0) {
     13         nex = N;
     14         v = V;
     15         len = L;
     16     }
     17 }edge[1000010]; int tp;
     18 
     19 std::queue<int> Q;
     20 int e[N], a[N], b[N], c[N], m, n, cnt[N], Time;
     21 LL d[N];
     22 bool vis[N];
     23 
     24 inline void add(int x, int y, LL z) {
     25     tp++;
     26     edge[tp] = Edge(e[x], y, z);
     27     e[x] = tp;
     28     return;
     29 }
     30 
     31 inline int spfa(int s) {
     32     memset(d, 0x3f, sizeof(d));
     33     memset(cnt, 0, sizeof(cnt));
     34     vis[s] = Time;
     35     d[s] = 0;
     36     cnt[s] = 1;
     37     Q.push(s);
     38     while(!Q.empty()) {
     39         int x = Q.front();
     40         Q.pop();
     41         vis[x] = 0;
     42         for(int i = e[x]; i; i = edge[i].nex) {
     43             int y = edge[i].v;
     44             if(d[y] > d[x] + edge[i].len) {
     45                 d[y] = d[x] + edge[i].len;
     46                 cnt[y] = cnt[x] + 1;
     47                 if(cnt[y] > n + 1) {
     48                     return -1;
     49                 }
     50                 if(vis[y] != Time) {
     51                     vis[y] = Time;
     52                     Q.push(y);
     53                 }
     54             }
     55         }
     56     }
     57     return 0;
     58 }
     59 
     60 char str[4];
     61 
     62 int main() {
     63     //printf("%d 
    ", (sizeof(edge) + sizeof(cnt) * 7) / 1048576);
     64     while(scanf("%d", &n), n) {
     65         memset(e, 0, sizeof(e));
     66         Time++;
     67         int x, y;
     68         tp = 0;
     69         for(int i = 1; i <= n; i++) {
     70             scanf("%d", &a[i]);
     71         }
     72         while(scanf("%s", str)) {
     73             if(str[0] == '#') break;
     74             scanf("%d%d", &x, &y);
     75             if(str[0] == 'F' && str[2] == 'S') {
     76                 add(y, x, a[x]);
     77             }
     78             else if(str[0] == 'F') {
     79                 add(y, x, -a[y] + a[x]);
     80             }
     81             else if(str[2] == 'F') {
     82                 add(y, x, -a[y]);
     83             }
     84             else {
     85                 add(y, x, 0);
     86             }
     87         }
     88         for(int i = 1; i <= n; i++) {
     89             add(n + 1, i, 0);
     90         }
     91         int t = spfa(n + 1);
     92         printf("Case %d:
    ", Time);
     93         if(t == -1) {
     94             printf("impossible
    ");
     95         }
     96         else {
     97             for(int i = 1; i <= n; i++) {
     98                 printf("%d %d
    ", i, -d[i]);
     99             }
    100         }
    101         puts("");
    102     }
    103     return 0;
    104 }
    AC代码

    HDU1529 Cashier Employment 把每个时间的选用人数做前缀和。发现有7个不等式有三个变量,于是二分其中一个,也就是总共选了多少人。

      1 #include <bits/stdc++.h>
      2 
      3 typedef long long LL;
      4 const int N = 110;
      5 
      6 struct Edge {
      7     int nex, v;
      8     LL len;
      9     Edge(int N = 0, int V = 0, LL L = 0) {
     10         nex = N;
     11         v = V;
     12         len = L;
     13     }
     14 }edge[100010]; int tp;
     15 
     16 int e[N], cnt[N], stk[N], top, n, m, a[N], vis[N], b[N];
     17 LL d[N];
     18 
     19 inline void add(int x, int y, LL z) {
     20     tp++;
     21     edge[tp] = Edge(e[x], y, z);
     22     e[x] = tp;
     23     return;
     24 }
     25 
     26 inline int spfa(int s) {
     27     static int Time = 0;
     28     Time++;
     29     memset(d, 0x3f, sizeof(d));
     30     memset(cnt, 0, sizeof(cnt));
     31     stk[++top] = s;
     32     vis[s] = Time;
     33     cnt[s] = 1;
     34     d[s] = 0;
     35     while(top) {
     36         int x = stk[top];
     37         top--;
     38         vis[x] = 0;
     39         for(int i = e[x]; i; i = edge[i].nex) {
     40             int y = edge[i].v;
     41             if(d[y] > d[x] + edge[i].len) {
     42                 d[y] = d[x] + edge[i].len;
     43                 cnt[y] = cnt[x] + 1;
     44                 if(cnt[y] > n + 1) {
     45                     return -1;
     46                 }
     47                 if(vis[y] != Time) {
     48                     vis[y] = Time;
     49                     stk[++top] = y;
     50                 }
     51             }
     52         }
     53     }
     54     return 0;
     55 }
     56 
     57 inline void clear() {
     58     memset(b, 0, sizeof(b));
     59     tp = 0;
     60     return;
     61 }
     62 
     63 inline bool check(int mid) {
     64     memset(e, 0, sizeof(e));
     65     tp = 0;
     66     for(int i = 1; i <= n; i++) {
     67         add(i, i + 1, 0);
     68         if(i < 8) {
     69             add(i + 17, i + 1, -a[i] + mid);
     70         }
     71         else {
     72             add(i - 7, i + 1, -a[i]);
     73         }
     74         add(i + 1, i, b[i]);
     75     }
     76     add(1, n + 1, -mid);
     77     add(n + 1, 1, mid);
     78     int t = spfa(1);
     79     return t != -1;
     80 }
     81 
     82 inline void solve() {
     83     n = 24;
     84     for(int i = 1; i <= n; i++) {
     85         scanf("%d", &a[i]);
     86     }
     87     scanf("%d", &m);
     88     for(int i = 1; i <= m; i++) {
     89         int x;
     90         scanf("%d", &x);
     91         b[x + 1]++;
     92     }
     93     /// calc
     94     int l = 0, r = m + 1;
     95     while(l < r) {
     96         int mid = (l + r) >> 1;
     97         if(check(mid)) {
     98             r = mid;
     99         }
    100         else {
    101             l = mid + 1;
    102         }
    103     }
    104     if(r == m + 1) {
    105         printf("No Solution
    ");
    106         return;
    107     }
    108     printf("%d
    ", r);
    109     return;
    110 }
    111 
    112 int main() {
    113     int T;
    114     scanf("%d", &T);
    115     while(T--) {
    116         solve();
    117         if(T) {
    118             clear();
    119         }
    120     }
    121     return 0;
    122 }
    AC代码
  • 相关阅读:
    [LeetCode] 1081. Smallest Subsequence of Distinct Characters 不同字符的最小子序列
    [LeetCode] 1080. Insufficient Nodes in Root to Leaf Paths 根到叶路径上的不足节点
    [LeetCode] 1079. Letter Tile Possibilities 活字印刷
    [LeetCode] 1078. Occurrences After Bigram 双元语法分词
    [LeetCode] 1074. Number of Submatrices That Sum to Target 元素和为目标值的子矩阵数量
    [LeetCode] 1073. Adding Two Negabinary Numbers 负二进制数相加
    [LeetCode] 1072. Flip Columns For Maximum Number of Equal Rows 按列翻转得到最大值等行数
    [LeetCode] 1071. Greatest Common Divisor of Strings 字符串的最大公因子
    [LeetCode] 1054. Distant Barcodes 距离相等的条形码
    [LeetCode] 1053. Previous Permutation With One Swap 交换一次的先前全排列
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10448363.html
Copyright © 2011-2022 走看看