1. 程式人生 > >bzoj1731: [Usaco2005 dec]Layout 排隊佈局(差分約束)

bzoj1731: [Usaco2005 dec]Layout 排隊佈局(差分約束)

原題連結

題目描述:當排隊等候餵食時,奶牛喜歡和它們的朋友站得靠近些。FJ有N(2<=N<=1000)頭奶牛,編號從1到N,沿一條直線站著等候餵食。奶牛排在隊伍中的順序和它們的編號是相同的。因為奶牛相當苗條,所以可能有兩頭或者更多奶牛站在同一位置上。即使說,如果我們想象奶牛是站在一條數軸上的話,允許有兩頭或更多奶牛擁有相同的橫座標。一些奶牛相互間存有好感,它們希望兩者之間的距離不超過一個給定的數L。另一方面,一些奶牛相互間非常反感,它們希望兩者間的距離不小於一個給定的數D。給出ML條關於兩頭奶牛間有好感的描述,再給出MD條關於兩頭奶牛間存有反感的描述。(1<=ML,MD<=10000,1<=L,D<=1000000)你的工作是:如果不存在滿足要求的方案,輸出-1;如果1號奶牛和N號奶牛間的距離可以任意大,輸出-2;否則,計算出在滿足所有要求的情況下,1號奶牛和N號奶牛間可能的最大距離。

輸入格式:第一行:三個整數n,Ml,Md,用空格分隔。
第2 ~ Ml+1行:每行三個整數a,b,c。表述a與b之間的距離應≤c。保證a < b。
第Ml+2 ~ ML+Md+1行:每行三個整數a,b,c。表述a與b之間的距離應≥D 。保證a < b。

輸出格式:一行,一個整數。如果沒有合法方案,輸出 -1. 如果有合法方案,但 1 號奶牛可以與 N 號奶牛相距無窮遠,輸出 -2. 否則,輸出 1 號奶牛與 N 號奶牛間的最大距離。

輸入樣例
4 2 1
1 3 10
2 4 20
2 3 3

輸出樣例
27

解析:一道差分約束的經典題。
   由題意,可知要求\(d_b-d_a≤D,d_d-d_c≥D,d_{i+1}-d_{i}≥0\)


   即\(d_b-d_a≤D,d_c-d_d≤D,d_{i}-d_{i+1}≤0\)
   所以建邊後有spfa跑一次最短路即可。
   若存在負環,則輸出-1。若無法連通,則輸出-2。

程式碼如下:

#include<cstdio>
#include<queue>
using namespace std;
 
const int maxn = 1e5 + 5 ;
int n, l, d, dis[maxn], vis[maxn], cnt[maxn];
int nxt[maxn], hed[maxn], to[maxn], val[maxn], tot;
queue <int> que;
 
int read(void) {
    char c; while (c = getchar(), c < '0' || c > '9'); int x = c - '0';
    while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x;
}
 
void add(int x, int y, int v) {
    nxt[++ tot] = hed[x]; hed[x] = tot; to[tot] = y; val[tot] = v;
}
 
int spfa(void) {
      for (int i = 1; i <= n; ++ i) dis[i] = 2e9;
    vis[1] = 1; dis[1] = 0; cnt[1] = 1; que.push(1);
      while (!que.empty()) {
        int u = que.front(); vis[u] = 0; que.pop();
          for (int i = hed[u]; i ; i = nxt[i]) {
            int v = to[i];
              if (dis[v] > dis[u] + val[i]) {
                dis[v] = dis[u] + val[i];
                if (!vis[v]) {
                  if (++ cnt[v] > n) return -1;
                  vis[v] = 1; 
                  que.push(v);
                }
              }
          }
      }
    if (dis[n] == 2e9) return -2;
    return dis[n];
}
 
int main() {
    n = read(); l = read(); d = read();
      for (int i = 2; i <= n; ++ i) add(i, i - 1, 0);
      for (int i = 1; i <= l; ++ i) {
        int x = read(), y = read(), v = read();
        add(x, y, v);
      }
      for (int i = 1; i <= d; ++ i) {
        int x = read(), y = read(), v = read();
        add(y, x, -v);
      }
    printf("%d", spfa());
    return 0;
}