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

  • 相关阅读:
    【AppScan心得】IBM Rational AppScan 无法记录登录序列
    tomcat记录XForwardedFor字段中的远程IP
    【AppScan深入浅出】修复漏洞:会话标识未更新(中危)
    用java在Windows控制台输出utf8字符
    【图解漏洞】图解跨站脚本攻击(XSS)原理
    【图解漏洞】图解跨站请求伪造(CSRF)原理(之二)
    雅克比矩阵(Jacobian Matrix)在正运动学中的应用
    游戏物理引擎之静态碰撞
    万向节死锁(Gimbal Lock)
    旋转矩阵(Rotate Matrix)的性质分析
  • 原文地址:https://www.cnblogs.com/xixike/p/15540751.html
Copyright © 2011-2022 走看看