1. 程式人生 > >UVA-11478 Halum【二分】【差分約束】

UVA-11478 Halum【二分】【差分約束】

LINK1

LINK2


題目大意

給你一個n個點,m條邊的有向圖

有一種操作把所有到達這個點的邊全部減小d,把所有從從這個點出發的邊加上d

問最後是否可以讓所有邊的邊權最小值最大

如果可以無限大,輸出\(Infinite\),如果不能讓所有邊權非負,輸出\(No\ solution\)


思路

最小值最大

就可以考慮二分了

然後發現對於任意一個點

所有在這個點上的操作是可以累加起來的,這樣我們就可以令\(c_u\)表示在u這個節點上的操作值的總和

那麼對於一條有向邊\((u,v)\),邊權是\(mid\le w_{u,v}+c_u-c_v\)

轉換成\(c_v-c_u\le w_{u,v}-mid\)

就把\(v\)\(u\)連上長度是\(w_{u,v}-mid\)的邊

然後深搜spfa判斷負環就可以啦

為啥不廣搜?

廣搜1000ms深搜10ms你選哪一個?


在實際實現中其實發現c的正負沒有影響

所以咋推式子都行我寫程式碼和寫題解推的式子都不一樣


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
  bool w = 1;x = 0;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') w = 0, c = getchar();
  while (isdigit(c)) {
    x = (x<<1) + (x<<3) + c -'0';
    c = getchar();
  }
  if (!w) x = -x;
}
template <typename T>
void Write(T x) {
  if (x < 0) {
    putchar('-');
    x = -x;
  }
  if (x > 9) Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 1e5 + 10;
struct Edge {
  int v, w, nxt;
} E[N];
int fro[N], to[N], val[N];
int dis[N], inq[N];
int head[N], tot, n, m; 

void add(int u, int v, int w) {
  E[++tot] = (Edge) {v, w, head[u]};
  head[u] = tot;
}

void init() {
  fu(i, 1, n) dis[i] = INF_of_int;
  fu(i, 1, n) head[i] = inq[i] = 0;
  tot = 0;
}

bool spfa(int u) {
  inq[u] = 1;
  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 (inq[v] || (!inq[v] && !spfa(v))) return 0;
    }
  }
  inq[u] = 0;
  return 1;
}
/*
bool spfa() {
  static queue<int> q;
  fu(i, 1, n) inq[i] = 1, q.push(i);
  while (q.size()) {
    int u = q.front(); q.pop();
    inq[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 (!inq[v]) {
          if (++vis[v] >= n) return 0;
          else inq[v] = 1, q.push(v);
        } 
      }
    }
  }
  return 1;
}
*/
bool check(int key) {
  init();
  fu(i, 1, m) 
    add(to[i], fro[i], val[i] - key);
  fu(i, 1, n) if (!spfa(i)) return 0;
  return 1;
}

void work() {
  int l = 1, r = 1;
  fu(i, 1, m) {
    Read(fro[i]), Read(to[i]), Read(val[i]);
    r = max(r, val[i]);
  }
  if (check(r)) {printf("Infinite\n");}
  else if (!check(l)) {printf("No Solution\n");}
  else {
    int res = 1;
    while (l <= r) {
      int mid = (l + r) >> 1;
      if (check(mid)) l = mid + 1, res = mid;
      else r = mid - 1;
    }
    Write(res), putchar('\n');
  }
}

int main() {
#ifdef dream_maker
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
#endif
  while (scanf("%d %d", &n, &m) != EOF) work();
}