题目
题目背景
2008四川NOI省选
题目描述
你有n个砝码,均为1克,2克或者3克。你并不清楚每个砝码的重量,但你知道其中一些砝码重量的大小关系。你把其中两个砝码A 和B 放在天平的左边,需要另外选出两个砝码放在天平的右边。问:有多少种选法使得天平的左边重(c1)、一样重(c2)、右边重(c3)?(只有结果保证惟一的选法才统计在内)
输入格式
第一行包含三个正整数n,A,B(1<=A,B<=N,A 和B 不相等)。砝码编号
为1~N。以下n行包含重量关系矩阵,其中第i行第j个字符为加号“+”表示砝
码i比砝码j重,减号“-”表示砝码i比砝码j 轻,等号“=”表示砝码i和砝码
j一样重,问号“?”表示二者的关系未知。存在一种情况符合该矩阵。
输出格式
仅一行,包含三个整数,即c1,c2和c3。
输入输出样例
输入 #1 复制
6 2 5
?+???
-?+???
?-???
???+?
???-?+
???-?
输出 #1 复制
1 4 1
输入 #2 复制
14 8 4
?+???++???++
-??=?=???=
???=???
?=??+?==???
???-???-???-??
-=???
-??=???=?-+???
???=+?=???
???
???+???
??=???-???-??
???+???+???
-???
-=???
输出 #2 复制
18 12 11
说明/提示
4<=n<=50
思路
首先我们考虑某个砝码质量大于或小于另一个砝码的状况下对砝码质量(或者更确切来讲,是质量差)的限制。
又由于砝码只有 1、2、3 三种质量,我们就可以通过质量关系得到两个砝码最多差多少克、最少差多少克。然后用 floyd 对砝码间的质量差进行上下界的确定,最后 爆枚 出解就好了
代码
#include<bits/stdc++.h>
using namespace std;
const int M=55; char a[M];
int n,len,s1,s2,c1,c2,c3;
int dx[M][M],dn[M][M];
inline void cmin(int& a,int b){if(a>b)a=b;}
inline void cmax(int& a,int b){if(a<b)a=b;}
int main(){
scanf("%d%d%d",&n,&s1,&s2);
for(int i=1;i<=n;++i){
scanf("%s",a),len=strlen(a);
for(int j=0;j<len;++j)
if(a[j]=='='||i==j+1)
dx[i][j+1]=dn[i][j+1]=0;
else if(a[j]=='+')
dx[i][j+1]=2,dn[i][j+1]=1;
else if(a[j]=='-')
dx[i][j+1]=-1,dn[i][j+1]=-2;
else dx[i][j+1]=2,dn[i][j+1]=-2;
}
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i) if(i^k)
for(int j=1;j<=n;++j) if(j^k&&i^j)
cmin(dx[i][j],dx[i][k]+dx[k][j]),
cmax(dn[i][j],dn[i][k]+dn[k][j]);
for(int i=1;i<=n;++i)if(i^s1&&i^s2)
for(int j=1;j<i;++j) if(j^s1&&j^s2)
c1+=dn[s1][i]>dx[j][s2]||dn[s2][i]>dx[j][s1],
c3+=dn[i][s1]>dx[s2][j]||dn[i][s2]>dx[s1][j],
c2+=(dn[s1][i]==dx[s1][i]&&dn[j][s2]==dx[j][s2]&&dn[s1][i]==dn[j][s2])||
(dn[s1][j]==dx[s1][j]&&dn[i][s2]==dx[i][s2]&&dn[s1][j]==dn[i][s2]);
return !printf("%d %d %d\n",c1,c2,c3);
}