题目背景
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。
输入输出样例
说明
4<=n<=50
暴力:25
用拓扑排序确定每个点的重量,然后暴力枚举哪两个点。
但是拓扑序不确定,题目要求确定才能统计,所以WA+T+A
正解:
差分约束。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=60; 7 int Max[N][N],Min[N][N]; 8 char s[N]; 9 int n,A,B,c1,c2,c3; 10 void Floyd() 11 { 12 for(int k=1;k<=n;k++) 13 for(int i=1;i<=n;i++) 14 for(int j=1;j<=n;j++) 15 if(i!=k && i!=j && k!=j) 16 { 17 Max[i][j]=min(Max[i][j],Max[i][k]+Max[k][j]); 18 Min[i][j]=max(Min[i][j],Min[i][k]+Min[k][j]); 19 } 20 } 21 void work() 22 { 23 for(int i=1;i<=n;i++) 24 for(int j=1;j<i;j++) 25 if(i!=A && i!=B && j!=A && j!=B) 26 { 27 if(Min[A][i]>Max[j][B] || Min[A][j]>Max[i][B])c1++; 28 if(Max[A][i]<Min[j][B] || Max[B][i]<Min[j][A])c3++; 29 if(Max[A][i]==Min[A][i] && Max[j][B]==Min[j][B] && Max[A][i]==Max[j][B]) c2++; 30 else if(Max[A][j]==Min[A][j] && Max[i][B]==Min[i][B] && Max[A][j]==Max[i][B]) c2++; 31 } 32 printf("%d %d %d",c1,c2,c3); 33 } 34 int main() 35 { 36 scanf("%d%d%d",&n,&A,&B); 37 for(int i=1;i<=n;i++) 38 { 39 scanf("%s",s+1); 40 for(int j=1;j<=n;j++) 41 { 42 if(s[j]==‘=‘||i==j+1) Max[i][j]=0,Min[i][j]=0; 43 if(s[j]==‘+‘) Max[i][j]=2,Min[i][j]=1; 44 if(s[j]==‘-‘) Max[i][j]=-1,Min[i][j]=-2; 45 if(s[j]==‘?‘)Max[i][j]=2,Min[i][j]=-2; 46 } 47 } 48 Floyd(); 49 work(); 50 return 0; 51 }
死亡是最简单不过的事情,但真正困难的是光荣的活下去。