[Luogu P2474] [BZOJ 1077] [SCOI2008]天平

洛谷传送门

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 1A B ≤ N B\le N BN A A A B B B 不相等)。砝码编号为 1 ∼ N 1\sim N 1N。以下 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 4n50

解题分析

我们先用差分约束跑出两个砝码之间差值的最大和最小值, 然后枚举另外两个砝码, 判断情况是否唯一即可。

代码如下:

#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);
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页