[SCOI2008]天平

题目描述

你有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

A+B>C+D <=> A-C>D-B 由此我们可以使用差分约束

用数组Max[i][j],Min[i][j]分别表示 i-j 的最大值和最小值,使用Floyd

对这个数组用Floyd,就可以求出最终两点间的大小关系

Max[i][j]=min(Max[i][j],Max[i][k]+Max[k][j])

Min[i][j]=max(Min[i][j],Min[i][k]+Min[k][j])

拿Max来说明:比如i-j<=2,i-k<=1,k-j<=0

那么显然i-j条件就变成i-j<=1

于是判断就可以枚举两个砝码

如果Min[s1][i]>Max[j][s2]那么显然大小关系是确定的

就有s1-i>j-s2   =>   s1+s2>i+j  于是c1可以+1

c2和c3同理

zyys(贼有意思)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int Max[51][51],Min[51][51];
 7 char s[51];
 8 int n,s1,s2,c1,c2,c3;
 9 int main()
10 {int i,j,k,l;
11   cin>>n>>s1>>s2;
12   for (i=1;i<=n;i++)
13     {
14       scanf("%s",s);
15       l=strlen(s);
16       for (j=0;j<l;j++)
17     {
18       if (s[j]=='='||i==j+1)
19         Max[i][j+1]=0,Min[i][j+1]=0;
20       else 
21       if (s[j]=='+')
22         Max[i][j+1]=2,Min[i][j+1]=1;
23       else 
24       if (s[j]=='-')
25         Max[i][j+1]=-1,Min[i][j+1]=-2;
26       else 
27       if (s[j]=='?')
28         Max[i][j+1]=2,Min[i][j+1]=-2;
29     }    
30     }
31   for (k=1;k<=n;k++)
32     for (i=1;i<=n;i++)
33       if (i!=k)
34     {
35       for (j=1;j<=n;j++)
36         if (i!=j&&k!=j)
37           {
38         Max[i][j]=min(Max[i][j],Max[i][k]+Max[k][j]);
39         Min[i][j]=max(Min[i][j],Min[i][k]+Min[k][j]);
40           }
41       }
42   for (i=1;i<=n;i++)
43     if (i!=s1&&i!=s2)
44       {
45     for (j=1;j<i;j++)
46       if (j!=s1&&j!=s2)
47         {
48           if (Min[s1][i]>Max[j][s2]||Min[s1][j]>Max[i][s2])
49         c1++;
50           if (Max[s1][i]<Min[j][s2]||Max[s2][i]<Min[j][s1])
51         c3++;
52           if ((Max[s1][i]==Min[s1][i]&&Max[j][s2]==Min[j][s2]&&Max[s1][i]==Max[j][s2])||(Max[s1][j]==Min[s1][j]&&Max[i][s2]==Min[i][s2]&&Max[s1][j]==Max[i][s2])) c2++;
53         }
54       }
55   cout<<c1<<' '<<c2<<' '<<c3;
56 }

 

posted @ 2017-10-27 21:33  Z-Y-Y-S  阅读(339)  评论(0编辑  收藏  举报