神题,因为砝码的质量只有三种,所以,对于每一种关系,都有一个上下界,那么我们可以通过一个floyd来跑出各点之间的差值范围,然后暴力枚举出解
在爆枚过程中怎么判断是哪种情况呢
摘一下chen_zhe大佬的
若要满足
A
+
B
<
C
+
D
A+B<C+D
A+B<C+D,那么只要满足
A
−
C
<
D
−
B
A−C<D−B
A−C<D−B或者
A
−
D
<
C
−
B
A−D<C−B
A−D<C−B就可以了
如果 A − C < D − B A−C<D−B A−C<D−B一定成立,那么 max ( A − C ) < min ( D − B ) \max(A-C)<\min(D-B) max(A−C)<min(D−B),A−D<C−B同理
若要满足 A + B = C + D A+B=C+D A+B=C+D,那么只要满足 A − C = D − B A−C=D−B A−C=D−B或者 A − D = C − B A−D=C−B A−D=C−B就可以了
如果 A − C = D − B A−C=D−B A−C=D−B一定成立,那么 min ( A − c ) = max ( A − c ) = min ( D − B ) = max ( D − B ) \min(A-c)=\max(A-c)=\min(D-B)=\max(D-B) min(A−c)=max(A−c)=min(D−B)=max(D−B)
A − D = C − B A−D=C−B A−D=C−B同理, A + B > C + D A+B>C+D A+B>C+D同理
if(mn[s1][i]>mx[j][B] || mn[B][i]>mx[j][A])
c1++; //A+B>i+j <=> i-A<B-j
if(mn[i][A]>mx[B][j] || mn[i][B]>mx[A][j])
c3++; //i+j>A+B <=> i-A>B-j
if((mn[A][i]==mx[A][i] && mn[j][B]==mx[j][B] && mn[A][i]==mn[j][B]) ||
(mn[A][j]==mx[A][j] && mn[i][B]==mx[i][B] && mn[A][j]==mn[i][B]))
c2++; //由上可得
完整的
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 53;
int mx[maxn][maxn],mn[maxn][maxn];
int n,A,B,c1,c2,c3;
int main()
{
scanf("%d%d%d",&n,&A,&B);
for(int i=1;i<=n;++i)
{
char ch[maxn];
scanf("%s",ch+1);
for(int j=1;j<=n;j++)
{
if(ch[j]=='?')
{
mx[i][j]=2;
mn[i][j]=-2;
}
else if(ch[j]=='+')
{
mx[i][j]=2;
mn[i][j]=1;
}
else if(ch[j]=='-')
{
mx[i][j]=-1;
mn[i][j]=-2;
}
else
{
mx[i][j]=mn[i][j]=0;
}
}
}
for(int k=1;k<=n;k++)
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
if(i!=j&&i!=k&&k!=j)
{
mx[i][j]=min(mx[i][k]+mx[k][j],mx[i][j]);
mn[i][j]=max(mn[i][k]+mn[k][j],mn[i][j]);
}
for(int i=1;i<=n;i++)
{
if(i==A||i==B)continue;
for(int j=1;j<=n;j++)
{
if(i==j)continue;
if(j==A||j==B)continue;
if(mn[A][i]>mx[j][B]||mn[B][i]>mx[j][A])c1++;
if((mn[A][i]==mx[A][i]&&mn[j][B]==mx[j][B]&&mn[A][i]==mn[j][B])||(mn[A][j]==mx[A][j]&&mn[i][B]==mx[i][B]&&mn[A][j]==mn[i][B]))c2++;
if(mn[i][A]>mx[B][j]||mn[i][B]>mx[A][j])c3++;
}
}
printf("%d %d %d",c1/2,c2/2,c3/2);
}