洛谷传送门
BZOJ传送门
题目描述
你有 n n n个砝码,均为 1 1 1克, 2 2 2克或者 3 3 3克。你并不清楚每个砝码的重量,但你知道其中一些砝码重量的大小关系。你把其中两个砝码 A A A 和 B B B 放在天平的左边,需要另外选出两个砝码放在天平的右边。问:有多少种选法使得天平的左边重( c 1 c_1 c1)、一样重( c 2 c_2 c2)、右边重( c 3 c_3 c3)?(只有结果保证惟一的选法才统计在内)
输入输出格式
输入格式:
第一行包含三个正整数
n
n
n,
A
A
A,
B
B
B(
1
≤
A
1\le A
1≤A,
B
≤
N
B\le N
B≤N,
A
A
A 和
B
B
B 不相等)。砝码编号为
1
∼
N
1\sim N
1∼N。以下
n
n
n行包含重量关系矩阵,其中第
i
i
i行第
j
j
j个字符为加号+
表示砝码
i
i
i比砝码
j
j
j重,减号-
表示砝码
i
i
i比砝码
j
j
j 轻,等号=
表示砝码
i
i
i和砝码
j
j
j一样重,问号?
表示二者的关系未知。存在一种情况符合该矩阵。
输出格式:
仅一行,包含三个整数,即 c 1 c_1 c1, c 2 c_2 c2和 c 3 c_3 c3。
输入输出样例
输入样例#1:
6 2 5
?+????
-?+???
?-????
????+?
???-?+
????-?
输出样例#1:
1 4 1
输入样例#2:
14 8 4
?+???++?????++
-??=?=???????=
??????????=???
?=??+?==??????
???-???-???-??
-=????????????
-??=???=?-+???
???=+?=???????
??????????????
??????+???????
??=???-????-??
????+?????+???
-?????????????
-=????????????
输出样例#2:
18 12 11
说明
4 ≤ n ≤ 50 4\le n\le 50 4≤n≤50
解题分析
我们先用差分约束跑出两个砝码之间差值的最大和最小值, 然后枚举另外两个砝码, 判断情况是否唯一即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 55
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
int dmax[MX][MX], dmin[MX][MX];
int A, B, n;
char buf[MX];
int main(void)
{
in(n), in(A), in(B);
R int i, j, k;
for (i = 1; i <= n; ++i)
{
scanf("%s", buf + 1);
for (j = 1; j <= n; ++j)
{
if(buf[j] == '=' || i == j) dmax[i][j] = dmin[j][i] = 0;
else if(buf[j] == '+') dmax[i][j] = 2, dmin[i][j] = 1;
else if(buf[j] == '-') dmax[i][j] = -1, dmin[i][j] = -2;
else dmax[i][j] = 2, dmin[i][j] = -2;
}
}
for (k = 1; k <= n; ++k)
for (i = 1; i <= n; ++i) if(i ^ k)
for (j = 1; j <= n; ++j) if((i ^ j) && (j ^ k))
{
dmax[i][j] = min(dmax[i][j], dmax[i][k] + dmax[k][j]);
dmin[i][j] = max(dmin[i][j], dmin[i][k] + dmin[k][j]);
}
int ans1(0), ans2(0), ans3(0);
for (i = 1; i <= n; ++i) if((i ^ A) && (i ^ B))
{
for (j = i + 1; j <= n; ++j) if((j ^ A) && (j ^ B))
{
if(dmin[A][i] > dmax[j][B] || dmin[B][i] > dmax[j][A]) ans1++;
else if(dmax[A][i] < dmin[j][B] || dmax[B][i] < dmin[j][A]) ans3++;
else if((dmax[A][i] == dmin[A][i] && dmax[j][B] == dmin[j][B] && dmax[A][i] == dmin[j][B]) ||
(dmax[B][i] == dmin[B][i] && dmax[j][A] == dmin[j][A] && dmax[B][i] == dmin[j][A]))
ans2++;
}
}
printf("%d %d %d", ans1, ans2, ans3);
}