zoukankan      html  css  js  c++  java
  • UVA-11478 Halum【二分】【差分约束】

    LINK1

    LINK2


    题目大意

    给你一个n个点,m条边的有向图

    有一种操作把所有到达这个点的边全部减小d,把所有从从这个点出发的边加上d

    问最后是否可以让所有边的边权最小值最大

    如果可以无限大,输出(Infinite),如果不能让所有边权非负,输出(No solution)


    思路

    最小值最大

    就可以考虑二分了

    然后发现对于任意一个点

    所有在这个点上的操作是可以累加起来的,这样我们就可以令(c_u)表示在u这个节点上的操作值的总和

    那么对于一条有向边((u,v)),边权是(midle w_{u,v}+c_u-c_v)

    转换成(c_v-c_ule 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
    ");}
      else if (!check(l)) {printf("No Solution
    ");}
      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('
    ');
      }
    }
    
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
      freopen("output.txt", "w", stdout);
    #endif
      while (scanf("%d %d", &n, &m) != EOF) work();
    }
    
  • 相关阅读:
    团队开发第二阶段
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    C++类class和结构体struct区别
    c++简单的类的建立与参数的两种传递方法
    C++ 使用delete删除指针
    暂存
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9903173.html
Copyright © 2011-2022 走看看