1. 程式人生 > >洛谷P4878 [USACO05DEC]layout佈局

洛谷P4878 [USACO05DEC]layout佈局

題目描述

正如其他物種一樣,奶牛們也喜歡在排隊打飯時與它們的朋友挨在一起。\(FJ\) 有編號為 \(1\dots N\)\(N\) 頭奶牛 \((2\le N\le 1000)\)。開始時,奶牛們按照編號順序來排隊。奶牛們很笨拙,因此可能有多頭奶牛在同一位置上。

有些奶牛是好基友,它們希望彼此之間的距離小於等於某個數。有些奶牛是情敵,它們希望彼此之間的距離大於等於某個數。

給出 \(M_L\)​ 對好基友的編號,以及它們希望彼此之間的距離小於等於多少;又給出 \(M_D\)​ 對情敵的編號,以及它們希望彼此之間的距離大於等於多少 \((1≤M_L​, M_D\le 10^4)\)

請計算:如果滿足上述所有條件,\(1\)

號奶牛和 \(N\) 號奶牛之間的距離最大為多少。

輸入輸出格式

輸入格式

第一行:三個整數 \(N, M_L, M_D\)​,用空格分隔。

\(2\dots M_L+1\) 行:每行三個整數 \(A, B, D\),用空格分隔,表示 \(A\) 號奶牛與 \(B\) 號奶牛之間的距離須 \(\le D\)。保證 \(1\le A<B\le N\), \(1\le D\le 10^6\).

\(M_L+2\dots M_L+M_D+1\) 行:每行三個整數 \(A, B, D\),用空格分隔,表示 \(A\) 號奶牛與 \(B\) 號奶牛之間的距離須 \(\ge D\)

。保證 \(1\le A<B\le N\), \(1\le D\le 10^6\).

輸出格式

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

輸入輸出樣例

輸入樣例#1:

4 2 1
1 3 10
2 4 20
2 3 3

輸出樣例#1:

27

思路:

做這道題之前,大家應該先學習一下差分約束。

給大家推薦個部落格:不是我的……

然後回到這個題目上來,首先這道題有負環的出現,那顯然不能用\(dijkstra\)

了,那就把解法鎖定為\(spfa\)

對於給出的前\(M_L\)種關係:

就是這個樣子:\(d[B]-d[A] \leq D\)

\(M_D\)種關係是:\(d[B]-d[A] \geq D\),即\(d[A]-d[B] \leq -D\)

那對於第一種關係,根據差分約束,我們需要建從\(A\)\(B\),邊權為D的邊,對於第二種關係,我們就需要建從\(B\)\(A\),邊權為\(-D\)的邊。

這樣建完圖跑直接呼叫\(spfa(1)\)就可以得\(70\)分了,那為什麼不能\(AC\)
呢?

因為我們差分約束時的起點是\(0\),所以我們要先跑一遍\(spfa(0)\),並建一條從0到\(i(1 \leq i \leq n)\)的邊權為0的邊,為什麼呢?

難道不應該是\(d[0]-d[i] \leq 0\)麼?這樣不是應該從i到0的邊麼?但是,有沒有想過,如果你這樣建,那你以0為起點跑spfa有意義麼?0沒法到達任何一個點,所以,我們需要建一條從0到i的邊的邊權為0的邊。這樣這題就能AC啦!

自己整理的題解

下面是我醜陋(學長說的)的程式碼:

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<queue>
#define maxn 1007
using namespace std;
int num,n,m,p,head[maxn],dis[maxn],vis[maxn],in[maxn];
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
struct node {
  int v,w,nxt;
}e[20007];
inline void ct(int u, int v, int w) {
  e[++num].v=v;
  e[num].w=w;
  e[num].nxt=head[u];
  head[u]=num;
}
const int inf=0x3f3f3f3f;
inline void spfa(int s) {
  memset(dis,0x3f,sizeof(dis));
  memset(vis,0,sizeof(vis));
  memset(in,0,sizeof(in));
  queue<int>q;
  q.push(s),vis[s]=1,in[s]=1;
  dis[s]=0;
  while(!q.empty()) {
    int u=q.front();
    q.pop();vis[u]=0;
    for(int i=head[u];i;i=e[i].nxt) {
      int v=e[i].v;
      if(dis[v]>dis[u]+e[i].w) {
        dis[v]=dis[u]+e[i].w;
        if(!vis[v]) {
          vis[v]=1;
          in[v]++;
          if(in[v]>n) {
            printf("-1\n");
            exit(0);
          }
          q.push(v);
        }
      }
    }
  }
}
int main() {
  n=qread(),m=qread(),p=qread();
  for(int i=1,u,v,d;i<=m;++i) {
    u=qread(),v=qread(),d=qread();
    ct(u,v,d);
  }
  for(int i=1,u,v,d;i<=p;++i) {
    u=qread(),v=qread(),d=qread();
    ct(v,u,-d);
  }
  for(int i=1;i<=n;++i) ct(0,i,0);
  spfa(0);
  spfa(1);
  if(dis[n]==inf) {
    printf("-2\n");
    return 0;
  }
  printf("%d\n",dis[n]);
  return 0;
}