zoukankan      html  css  js  c++  java
  • 「题解」Solution P3275

    Description

    P3275
    给定 (n) 个整数 (t_i)(k) 个不等式,这 (k) 个不等式有如下几种

    • (t_i=t_j)
    • (t_i<t_j)
    • (t_i ge t_j)
    • (t_i>t_j)
    • (t_ile t_j)
      最后输出

    [sumlimits_{i=1}^nt_i ]

    如果无解输出 (-1)

    Solution

    建议先看一看差分约束前置知识。

    差分约束,但这种形式还是很难搞差分,所以我们要转化一下,成这样:

    • (t_i ge t_j) or (t_j ge t_i)
    • (t_j ge t_i+1)
    • (t_i ge t_j)
    • (t_i ge t_j+1)
    • (t_j ge t_i)

    我们一旦在差分约束题中发现 (a ge b) 的形式,那么我们就要开始算 最长路

    并且还有一个约束条件:(t_i >1)

    注意最长路与最短路的几个区别:

    • (dist_i=min{dist_j+<i,j>}) 的转化式要变为 (dist_i=max{dist_j+<i,j>})
    • (dist_i) 的初始值要从 ( m inf) 变为 ( m - inf)

    对于这道题,因为 (t_i > 1),所以在差分约束建超级源点的时候要注意边权 (w) 要设为 (1)

    然后根据差分约束模板的思路转化就可以。

    Code 1
    #include <bits/stdc++.h>
    
    using namespace std;
    
    struct node {
        int val, next, len;
    } e[1000086];
    
    int n, k;
    int cnt;
    int head[1000086];
    int dist[1000086];
    int sum[1000086];
    int vis[1000086];
    int S[1000086];
    const int inf = 0x3f3f3f3f;
    
    void AddEdge (int u, int v, int w) {
        e[++cnt].val = v;
        e[cnt].next = head[u];
        e[cnt].len = w;
        head[u] = cnt;
    }
    
    bool SPFA () {
        queue <int> q;
        int s = 0;
        for (int i = 1; i <= n; i++)
            dist[i] = -inf;
        dist[s] = 0;
        sum[s] = 1;
        vis[s]++;
        q.push(s);
        while (!q.empty()) {
            int cur = q.front();
            q.pop();
            sum[cur] = 0;
            for (int p = head[cur]; p > 0; p = e[p].next)
                if (dist[e[p].val] < dist[cur] + e[p].len) {
                    dist[e[p].val] = dist[cur] + e[p].len;
                    vis[e[p].val]++;
                    if (vis[e[p].val] >= n + 1)
                        return true;
                    if (!sum[e[p].val]) {
                        q.push(e[p].val);
                        sum[e[p].val] = 1;
                    }
                }
        }
        return false;
    }
    
    int main () {
        scanf("%d%d", &n, &k);
        for (int i = 1, opt, u, v; i <= k; i++) {
            scanf("%d%d%d", &opt, &u, &v);
            if (opt == 1) AddEdge(u, v, 0), AddEdge(v, u, 0);
            if (opt == 2) AddEdge(u, v, 1);
            if (opt == 3) AddEdge(v, u, 0);
            if (opt == 4) AddEdge(v, u, 1);
            if (opt == 5) AddEdge(u, v, 0);
        }
        for (int i = 1; i <= n; i++)
        	AddEdge(0, i, 1);
        if (SPFA()) {
        	printf("-1");
        	return 0;
    	}
        int ans = 0;
        for (int i = 1; i <= n; i++)
            ans += dist[i];
        printf("%d", ans);
        return 0;
    }
    

    预测得分:(80)
    wdnmd …… 这 TLE 是咋回事?

    所以我们要特判

    Code 2
    #include <bits/stdc++.h>
    
    using namespace std;
    
    struct node {
        int val, next, len;
    } e[1000086];
    
    int n, k;
    int cnt;
    int head[1000086];
    int dist[1000086];
    int sum[1000086];
    int vis[1000086];
    int S[1000086];
    const int inf = 0x3f3f3f3f;
    
    void AddEdge (int u, int v, int w) {
        e[++cnt].val = v;
        e[cnt].next = head[u];
        e[cnt].len = w;
        head[u] = cnt;
    }
    
    bool SPFA () {
        queue <int> q;
        int s = 0;
        for (int i = 1; i <= n; i++)
            dist[i] = -inf;
        dist[s] = 0;
        sum[s] = 1;
        vis[s]++;
        q.push(s);
        while (!q.empty()) {
            int cur = q.front();
            q.pop();
            sum[cur] = 0;
            for (int p = head[cur]; p > 0; p = e[p].next)
                if (dist[e[p].val] < dist[cur] + e[p].len) {
                    dist[e[p].val] = dist[cur] + e[p].len;
                    vis[e[p].val]++;
                    if (vis[e[p].val] >= n + 1)
                        return true;
                    if (!sum[e[p].val]) {
                        q.push(e[p].val);
                        sum[e[p].val] = 1;
                    }
                }
        }
        return false;
    }
    
    int main () {
        scanf("%d%d", &n, &k);
        for (int i = 1, opt, u, v; i <= k; i++) {
            scanf("%d%d%d", &opt, &u, &v);
            if (opt != 1 && opt != 3 && opt != 5 && u == v) {
            	printf("-1");
            	return 0;
    		}
            if (opt == 1) AddEdge(u, v, 0), AddEdge(v, u, 0);
            if (opt == 2) AddEdge(u, v, 1);
            if (opt == 3) AddEdge(v, u, 0);
            if (opt == 4) AddEdge(v, u, 1);
            if (opt == 5) AddEdge(u, v, 0);
        }
        for (int i = 1; i <= n; i++)
        	AddEdge(0, i, 1);
        if (SPFA()) {
        	printf("-1");
        	return 0;
    	}
        int ans = 0;
        for (int i = 1; i <= n; i++)
            ans += dist[i];
        printf("%d", ans);
        return 0;
    }
    

    预测得分:(90)
    这卡常 …… 还能卡一个 TLE

    那么我们还可以怎么优化呢?
    用 deque 一优化就可以了!

    Code 3
    #include <bits/stdc++.h>
    
    using namespace std;
    
    struct node {
        int val, next, len;
    } e[1000086];
    
    int n, k;
    int cnt;
    int head[1000086];
    int dist[1000086];
    int sum[1000086];
    int vis[1000086];
    int S[1000086];
    const int inf = 0x3f3f3f3f;
    
    void AddEdge (int u, int v, int w) {
        e[++cnt].val = v;
        e[cnt].next = head[u];
        e[cnt].len = w;
        head[u] = cnt;
    }
    
    bool SPFA () {
        deque <int> q;
        int s = 0;
        for (int i = 1; i <= n; i++)
            dist[i] = -inf;
        dist[s] = 0;
        sum[s] = 1;
        vis[s]++;
        q.push_front(s);
        while (!q.empty()) {
            int cur = q.front();
            q.pop_front();
            sum[cur] = 0;
            for (int p = head[cur]; p > 0; p = e[p].next)
                if (dist[e[p].val] < dist[cur] + e[p].len) {
                    dist[e[p].val] = dist[cur] + e[p].len;
                    vis[e[p].val]++;
                    if (vis[e[p].val] >= n + 1)
                        return true;
                    if (!sum[e[p].val]) {
                        q.push_front(e[p].val);
                        sum[e[p].val] = 1;
                    }
                }
        }
        return false;
    }
    
    int main () {
        scanf("%d%d", &n, &k);
        for (int i = 1, opt, u, v; i <= k; i++) {
            scanf("%d%d%d", &opt, &u, &v);
            if (opt != 1 && opt != 3 && opt != 5 && u == v) {
            	printf("-1");
            	return 0;
    		}
            if (opt == 1) AddEdge(u, v, 0), AddEdge(v, u, 0);
            if (opt == 2) AddEdge(u, v, 1);
            if (opt == 3) AddEdge(v, u, 0);
            if (opt == 4) AddEdge(v, u, 1);
            if (opt == 5) AddEdge(u, v, 0);
        }
        for (int i = 1; i <= n; i++)
        	AddEdge(0, i, 1);
        if (SPFA()) {
        	printf("-1");
        	return 0;
    	}
        long long ans = 0;
        for (int i = 1; i <= n; i++)
            ans += (1ll * dist[i]);
        printf("%lld", ans);
        return 0;
    }
    

    预测得分:(100)
    AC Record

    By Shuchong
    2020.7.15

  • 相关阅读:
    javascript实现动态侧边栏
    javascript实现图片滚动
    C语言-----野指针
    守护进程daemon.c
    UDP网络程序设计
    TCP网络程序设计
    网络编程模型
    fork和vfork
    网络协议分析
    多线程同步
  • 原文地址:https://www.cnblogs.com/Shu-chong/p/13303860.html
Copyright © 2011-2022 走看看