• BZOJ 2330


    传送门

    题目分析

    差分约束 这里做个简单介绍:形如(x_i - x_j >= d)的不等式,可以联想到我们求最短路时(d_v <= d_u + len),则上式可以变形为(x_i >= x_j + d)即连一条j->i的长度为d的边并跑最长路,dis[i]则是满足条件的最小解(因为上面等式采用的>=号,所以求出的时最小解,同理当变形为(x_j <= x_i - d) 采用<= 时求出的是最大解)。

    差分约束

    这道题也是经典的差分约束,只是要注意几个问题:

    • spfa判负环 无解
    • 输入矛盾条件时直接无解

    code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
     
    const int N = 1e6 + 5;
    typedef long long ll;
    const ll OO = 0x3f3f3f3f;
    int times[N];
    int n, k;
     
    ll dis[N];
    int ecnt, adj[N], go[N << 2], nxt[N << 2], len[N << 2];
    bool vst[N];
     
    inline void addEdge(int u, int v, int l){
        nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = l;
    }
     
    inline int read(){
        int i = 0, f = 1;char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
        if(ch == '-') ch = getchar(), f = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            i = (i << 3) + (i << 1) + (ch - '0');
        return i * f;
    }
     
    inline void wr(ll x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
     
    inline bool spfa(){
        static int que[N], qn;
        for(int i = 1; i <= n; i++) dis[i] = -OO;
        dis[0] = 0;
        que[qn = 1] = 0;
        vst[0] = true;
        for(int ql = 1; ql <= qn; ql++){
            int u = que[ql];
            vst[u] = false; 
            times[u]++;
            if(times[u] == n) return false;
            for(int e = adj[u]; e; e = nxt[e]){
                int v = go[e];
                if(dis[v] < dis[u] + len[e]){
                    dis[v] = dis[u] + len[e];
                    if(!vst[v]) vst[v] = true, que[++qn] = v;
                }
            }
        }
        return true;
    }
     
    int main(){
        n = read(), k = read();
        for(int i = n; i >= 1; i--) addEdge(0, i, 1);
        for(int i = 1; i <= k; i++){
            int x = read(), a = read(), b = read();
            switch(x){
                case 1:{
                    if(a != b){
                        addEdge(a, b, 0); 
                        addEdge(b, a, 0); 
                    }
                    break;
                }
                case 2:{
                    if(a == b){
                        printf("-1");
                        return 0;
                    }
                    addEdge(a, b, 1); 
                    break;
                }
                case 3:{
                    if(a != b)
                        addEdge(b, a, 0); 
                    break;
                }
                case 4:{
                    if(a == b){
                        printf("-1");
                        return 0;
                    }
                    addEdge(b, a, 1); 
                    break;
                }
                case 5:{
                    if(a != b)
                        addEdge(a, b, 0); 
                    break;
                }
                default: break;
            }
        }
        if(!spfa()){
            printf("-1");
            return 0;
        }
        ll ans = 0;
        for(int i = 1; i <= n; i++){
            ans += dis[i];
        }
        wr(ans);
        return 0;
    }
    
  • 相关阅读:
    JZOJ6096 森林
    HIT暑期集训 二分图匹配
    HIT暑期集训 网络流
    HIT暑期集训 tarjan,dfs序
    HIT暑期集训 图论基础
    HIT暑期集训 AC自动机
    HIT第二周 周测补题
    HIT暑期集训 字符串
    HIT暑期集训 动态规划
    HIT暑期集训 平衡树
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7482292.html
Copyright © 2020-2023  润新知