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();
}
posted @ 2018-11-04 10:01  Dream_maker_yk  阅读(148)  评论(0编辑  收藏  举报