zoukankan      html  css  js  c++  java
  • UVA11671 矩阵中的符号 Sign of Matrix 题解

    Description

    Luogu传送门

    Solution

    差分约束好题。

    看到矩阵上行列加减,不难想到差分约束。

    对于矩阵上的一个点 ((i,j))

    • $a_{i,j} = $ 0:那么 (x_i + y_j = 0)
    • $a_{i, j} = $ +:那么 (x_i + y_j geq 1)
    • $a_{i, j} = $ -:那么 (x_i + y_j leq -1)

    由于差分约束算法要求不等式的形式为 (a - b leq c)(a - b geq c),所以我们考虑对 (y_j) 取相反数。

    那么式子就变成了:

    • $a_{i, j} = $ 0(x_i - (-y_j) geq 0)(x_i - (-y_j) leq 0)
    • $a_{i, j} = $ +((-y_j) - x_i leq 1)
    • $a_{i, j} = $ -(x_i - (-y_j) leq -1)

    建图跑个最短路即可,若有负环则无解。

    我们跑最短路计算出来的 (dis) 数组就表示每一行,每一列达到目标条件所需要的步数(任意一组解),总步数就是把 (dis) 数组的值加起来。

    由于题目还要求我们求出最优解,我们可以对 (dis) 数组整体加上或减去同一个数。

    因为是同时加上或减去,所以 (dis) 数组内部的不等关系并没有变化,依然是一组解。

    那么同时加上多少才能让整个数组的和最小呢?

    类似于 糖果传递 那道题,我们取让 (dis) 数组同时减去它的中位数即可。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    
    using namespace std;
    
    const int N = 210;
    const int M = 1e4 + 10;
    int n, Case, ans;
    char s[N];
    struct node{
        int v, w, nxt;
    }edge[M << 1];
    int head[N], tot;
    int dis[N], vis[N], t[N];
    
    inline void add(int x, int y, int z){
        edge[++tot] = (node){y, z, head[x]};
        head[x] = tot;
    }
    
    inline bool spfa(){
        queue <int> q;
        for(int i = 1; i <= (n << 1); ++i)
            q.push(i), dis[i] = 0, vis[i] = t[i] = 1;
        while(!q.empty()){
            int x = q.front();
            q.pop();
            vis[x] = 0;
            for(int i = head[x]; i; i = edge[i].nxt){
                int y = edge[i].v;
                if(dis[y] > dis[x] + edge[i].w){
                    dis[y] = dis[x] + edge[i].w;
                    if(!vis[y]){
                        vis[y] = 1;
                        q.push(y);
                        if((++t[y]) > 2 * n + 1) return 0;
                    }
                }
            }
        }
        return 1;
    }
    
    int main(){
        while(scanf("%d", &n) && n != -1){
            memset(head, 0, sizeof(head));
            ans = tot = 0, Case++;
            for(int i = 1; i <= n; ++i){
                scanf("%s", s + 1);
                for(int j = 1; j <= n; ++j){
                    if(s[j] == '+') add(j + n, i, -1);
                    else if(s[j] == '-') add(i, j + n, -1);
                    else add(i, j + n, 0), add(j + n, i, 0);
                }
            }
            printf("Case %d: ", Case);
            if(spfa()){
                sort(dis + 1, dis + 1 + (n << 1));
                for(int i = 1; i <= (n << 1); ++i)
                    ans += abs(dis[i] - dis[n]);
                printf("%d
    ", ans);
            }else puts("-1");
        }
        return 0;
    }
    

    [\_EOF\_ ]

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15540751.html

  • 相关阅读:
    面向对象SOLID原则-设计模式-第2篇
    python 设计模式 开篇 第1篇
    区块链 第1篇 什么是区块链 区块链与比特币的关系 区块链的发展历史 应用领域
    HTTP协议六种请求:GET,HEAD,PUT,DELETE,POST
    python垃圾回收机制
    类的MRO属性 C3算法
    Vue第六篇 element-ui 项目管理工具npm webpack 启Vue项目vue-cli
    《EffctiveJava》泛型
    Kafka总结
    Windows 关闭端口号
  • 原文地址:https://www.cnblogs.com/xixike/p/15540751.html
Copyright © 2011-2022 走看看