重金20元求大佬帮我看一下这题我写的差分约束为啥错了
查看原帖
重金20元求大佬帮我看一下这题我写的差分约束为啥错了
291976
quanjun楼主2023/9/20 23:26

首先是我感觉我的建图和题解里的建图好像有点不一样,但是我感觉我这么建图然后差分约束没啥问题。有劳各位大佬在百忙之中帮忙看一下解答一下,我将向第一位给出正确解答的大佬发送 2020 元红包作为酬谢。万分感谢!

首先是我对差分约束建图的理解

首先是我对差分约束建图的理解(不知道对不对,可能在理解上就错了,恳请各位大佬帮忙指正):

如果我们用 valival_i 表示节点 ii 的权值,则:

情况一(求最短路)

若存在若干对如下所示的关系:

vali≤valj+Cval_i \le val_j + C(其中 CC 是一个常量),

则转换成图论模型后,应该建一条以节点 jj 为起点,以节点 ii 为终点的边权为 CC 的有向边。

建完边之后求最短路。

很明显,对于 vali≤valj+Cval_i \le val_j + C,因为 j→ij \rightarrow i 存在一条直连的边权为 CC 的边,所以从节点 jj 出发到达节点 ii 的最短路径长度肯定小于等于 CC 的,满足给定的条件。

情况二(求最长路)

若存在的关系都描述为:

vali≥valj+Cval_i \ge val_j + C

则其它条件都不变,建完边之后求最长路。

其次是这道题目的建图

因为这题涉及两个砝码差值的最大值和最小值,所以需要同时求最长路和最短路。

这里使用 floyd 算法把任意两点间的最短路和最长路都求出来。

这里:

  • 用 dxi,jdx_{i,j} 表示从节点 ii 出发到达节点 jj 的最长路径长度;
  • 用 dmi,jdm_{i,j} 表示从节点 ii 出发到达节点 jj 的最短路径长度。

然后接下来是考虑建图然后跑 floyd。

我们用 si,js_{i,j} 表示输入的二维字符矩阵第 ii 行第 jj 列的那个字符,同时用 valival_i 表示砝码的重量,那么,根据 si,js_{i,j} 的不同情况需要建不同的图,具体如下:

情况1:si,j=s_{i,j} = '+'

当 si,j=s_{i,j} = '+' 时,表示砝码 ii 比砝码 jj 重。

此时,有三种合法情况(因为砝码的重量只有可能是 11、22 或 33 克):

  1. vali=3,valj=2val_i = 3, val_j = 2
  2. vali=3,valj=1val_i = 3, val_j = 1
  3. vali=2,valj=1val_i = 2, val_j = 1

可以发现,此时砝码 ii 至少比砝码 jj 重 11 克,但不会比砝码 jj 重超过 22 克。

此时可以得到如下两个不等式:

  1. vali≥valj+1val_i \ge val_j + 1
  2. vali≤valj+2val_i \le val_j + 2

此时令:

  • dxj,i=1dx_{j, i} = 1:表示在求最长路的图中,以节点 ii 为起点,节点 jj 为终点连一条长度为 11 的有向边;
  • dmj,i=2dm_{j, i} = 2:表示在求最短路的图中,以节点 ii 为起点,节点 jj 为终点连一条长度为 22 的有向边。

情况2:si,j=s_{i,j} = '-'

当 si,j=s_{i,j} = '-' 时,表示砝码 ii 比砝码 jj 轻。

此时,有三种合法情况:

  1. vali=1,valj=2val_i = 1, val_j = 2
  2. vali=1,valj=3val_i = 1, val_j = 3
  3. vali=2,valj=3val_i = 2, val_j = 3

可以发现,此时砝码 ii 至少比砝码 jj 轻 11 克,但不会比砝码 jj 轻超过 22 克。

此时可以得到如下两个不等式:

  1. vali≥valj−2val_i \ge val_j - 2
  2. vali≤valj−1val_i \le val_j - 1

此时令:

  • dxj,i=−2dx_{j,i} = -2:表示在求最长路的图中,以节点 ii 为起点,节点 jj 为终点连一条长度为 −2-2 的有向边;
  • dmj,i=−1dm_{j,i} = -1:表示在求最短路的图中,以节点 ii 为起点,节点 jj 为终点连一条长度为 −1-1 的有向边。

情况3:si,j=s_{i,j} = '=' 或者 i=ji = j

当 i=ji = j 或 si,j=s_{i,j} = '=' 时,表示砝码 ii 和砝码 jj 的重量相等,此时

vali=valjval_i = val_j

可以推导出如下两个不等式:

  1. vali≥valj+0val_i \ge val_j + 0
  2. vali≤valj+0val_i \le val_j + 0

此时令:

  • dxj,i=0dx_{j,i} = 0:表示在求最长路的图中,以节点 ii 为起点,节点 jj 为终点连一条长度为 00 的有向边;
  • dmj,i=0dm_{j,i} = 0:表示在求最短路的图中,以节点 ii 为起点,节点 jj 为终点连一条长度为 00 的有向边。

情况4:si,j=s_{i,j} = '?'

当 si,j=s_{i,j} = '?' 时,此时所有情况都是有可能的(即 vali∈{1,2,3}val_i \in \{1,2,3\} 且 valj∈{1,2,3}val_j \in \{1,2,3\}),但砝码 ii 和砝码 jj 的质量相差不会超过 22 克,继而可以推出如下两个不等式:

  1. vali≥valj−2val_i \ge val_j - 2
  2. vali≤valj+2val_i \le val_j + 2

此时令:

  • dxj,i=−2dx_{j,i} = -2:表示在求最长路的图中,以节点 ii 为起点,节点 jj 为终点连一条长度为 00 的有向边;
  • dmj,i=2dm_{j,i} = 2:表示在求最短路的图中,以节点 ii 为起点,节点 jj 为终点连一条长度为 00 的有向边。

这样就建好图了,然后跑一遍 floyd。

跑完 floyd 之后:

  • dxj,idx_{j,i} 表示的是 jj 到 ii 的最长路径长度,它的实际含义是:vali−valjval_i - val_j 的最大值;
  • dmj,idm_{j,i} 表示的是 jj 到 ii 的最短路径长度,它的实际含义是:vali−valjval_i - val_j 的最小值。

最后是建完图之后枚举所有情况

因为天平的左边放的是砝码 AA 和 BB,所以我这边设天平的右边放的是砝码 ii 和 jj,并枚举 ii 和 jj。

因为 ”选砝码 ii 和 jj” 与 ”选砝码 jj 和 ii” 是等价的,所以在枚举的时候是按照:

for i ← 1 to n-1
    for j ← i+1 to n

的方式来枚举,并且保证 A,B,i,jA, B, i, j 各不相同,这样能做到不重不漏。

然后是分情况讨论 valA+valBval_A + val_B(即砝码 AA 和 BB 的重量之和)是否一定 大于、小于 或 等于 vali+valjval_i + val_j(即砝码 ii 和 jj 的重量之和)。

情况1:天平的左边重

此时满足条件:

valA+valB>vali+valjval_A + val_B \gt val_i + val_j

上式等价于:

  • valA−vali>valj−valBval_A - val_i \gt val_j - val_B,①
  • 或 valA−valj>vali−valBval_A - val_j \gt val_i - val_B,②

只需要 valA−valival_A - val_i 的最小值大于 valj−valBval_j - val_B 的最大值, ① 式必然成立。

而 dmi,Adm_{i,A} 表示的就是valA−valival_A - val_i 的最小值,dxB,jdx_{B,j} 表示的就是 valj−valBval_j - val_B 的最大值,所以只需要满足 dmi,A>dxB,jdm_{i,A} \gt dx_{B,j} 则 ① 式必然成立。

同理,只需要满足 dmj,A>dxB,jdm_{j,A} \gt dx_{B,j} 则 ② 式必然成立。

总结:

当 dmi,A>dxB,jdm_{i,A} \gt dx_{B,j} 或 dmj,A>dxB,jdm_{j,A} \gt dx_{B,j} 时,一定是天平的左边重。

情况2:天平的左右两边一样重

此时满足条件:

valA+valB=vali+valjval_A + val_B = val_i + val_j

上式等价于:

  • valA−vali=valj−valBval_A - val_i = val_j - val_B,①
  • 或 valA−valj=vali−valBval_A - val_j = val_i - val_B,②

对于 ① 式,这等价于说 ii 到 AA 的距离是一个固定值,同时 BB 到 jj 的距离也是这一个固定值(无论是在最短路对应的图还是在最长路对应的图中),所以只需要满足 dxi,A=dmi,A=dxB,j=dmB,jdx_{i,A} = dm_{i,A} = dx_{B,j} = dm_{B,j} 则 ① 式必然成立。

同理,只需要满足 dxj,A=dmj,A=dxB,i=dmB,idx_{j,A} = dm_{j,A} = dx_{B,i} = dm_{B,i} 则 ② 式必然成立。

总结:

当 dxi,A=dmi,A=dxB,j=dmB,jdx_{i,A} = dm_{i,A} = dx_{B,j} = dm_{B,j} 或 dxj,A=dmj,A=dxB,i=dmB,idx_{j,A} = dm_{j,A} = dx_{B,i} = dm_{B,i} 时,一定是天平的左右两边一样重。

情况3:天平的右边重

此时满足条件:

valA+valB<vali+valjval_A + val_B \lt val_i + val_j

上式等价于:

  • valA−vali<valj−valBval_A - val_i \lt val_j - val_B,①
  • 或 valA−valj<vali−valBval_A - val_j \lt val_i - val_B,②

只需要 valA−valival_A - val_i 的最大值小于 valj−valBval_j - val_B 的最小值, ① 式必然成立。

而 dxi,Adx_{i,A} 表示的就是valA−valival_A - val_i 的最大值,dmB,jdm_{B,j} 表示的就是 valj−valBval_j - val_B 的最小值,所以只需要满足 dxi,A<dmB,jdx_{i,A} \lt dm_{B,j} 则 ① 式必然成立。

同理,只需要满足 dxj,A<dmB,idx_{j,A} \lt dm_{B,i} 则 ② 式必然成立。

总结:

当 dxi,A<dmB,jdx_{i,A} \lt dm_{B,j} 或 dxj,A<dmB,idx_{j,A} \lt dm_{B,i} 时,一定是天平的左边重。

代码

根据上面的推导,编写的程序如下(但是错了,样例2都没对):

为了写起来方便起见,下标从 00 到 n−1n-1。

#include <bits/stdc++.h>
using namespace std;
int n, A, B, dx[55][55], dm[55][55];
char s[55][55];

// 一个辅助的函数,用来判断4个数的数值是否相同
bool equal4(int a, int b, int c, int d) {
    return a == b && b == c && c == d;
}

int main() {
    scanf("%d%d%d", &n, &A, &B);
    A--, B--;
    for (int i = 0; i < n; i++)
        scanf("%s", s[i]);
    // 建图
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (s[i][j] == '+')
                dx[j][i] = 1, dm[j][i] = 2;
            else if (s[i][j] == '-')
                dx[j][i] = -2, dm[j][i] = -1;
            else if (i == j || s[i][j] == '=')
                dx[j][i] = dm[j][i] = 0;
            else // s[i][j] == '?'
                dx[j][i] = -2, dm[j][i] = 2;
        }
    }
    // floyd
    for (int k = 0; k < n; k++)
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                dx[i][j] = max(dx[i][j], dx[i][k] + dx[k][j]),
                dm[i][j] = min(dm[i][j], dm[i][k] + dm[k][j]);
    // 枚举 i 和 j
    int c1 = 0, c2 = 0, c3 = 0; // 和题目对应
    for (int i = 0; i < n; i++) {
        if (i == A || i == B) continue;
        for (int j = i+1; j < n; j++) {
            if (j == A || j == B) continue;
            if (dm[i][A] > dx[B][j] || dm[j][A] > dx[B][i])
                c1++;
            if (equal4(dx[i][A], dm[i][A], dx[B][j], dm[B][j]) || equal4(dx[j][A], dm[j][A], dx[B][i], dm[B][i]))
                c2++;
            if (dx[i][A] < dm[B][j] || dx[j][A] < dm[B][i])
                c3++;
        }
    }
    printf("%d %d %d\n", c1, c2, c3);
    return 0;
}

有劳各位大佬帮忙看一下哪里出问题了,我将向第一位给出正确解答的大佬发送 2020 元红包作为酬谢。万分感谢!

2023/9/20 23:26
加载中...