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

原文地址:https://www.cnblogs.com/xixike/p/15540751.html