题目描述
传送门
题解
这道题n的范围很小,所以我们可以考虑枚举+判定
设放在天平右边的是C,D.
以
A+B<C+D
为例,因为差分约束必须是差的形式,所以我们将式子变形
B−C<D−A
然后枚举D,A的取值,就得到了一个关于两个数差的不等式。设枚举的A的值为x,那么
x<=A<=x
这个式子要想转换成差分的形式,需要引入一个新变量0,设
dis[0]=0
,那么式子可以变成
x<=A−0<=x
注意每个点都只能从[1,3]中取值,所以隐含的限制就是
1<=dis[i]−dis[0]<=3
。
题目中说只有结果保证惟一的选法才统计在内,意思是对于同一对C,D只能计算一次,且如果枚举的C,D的值不同,得到的与A+B的关系不同的话,那么方案不合法。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 100003
#define inf 1000000000
using namespace std;
int tot,nxt[N],point[N],v[N],c[N],mp[103][103],ans[5];
int can[N],dis[N],n,B,A,rec[10];
bool pd;
void add(int x,int y,int z)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
// cout<<x<<" "<<y<<" "<<z<<endl;
}
void spfa(int x)
{
can[x]=1;
for (int i=point[x];i;i=nxt[i])
if (dis[v[i]]>dis[x]+c[i]) {
dis[v[i]]=dis[x]+c[i];
if (can[v[i]]) {
pd=true;
return;
}
spfa(v[i]);
if (pd) return;
}
can[x]=0;
}
void build()
{
pd=false;
for (int i=0;i<=n;i++) dis[i]=inf,can[i]=0;
dis[0]=0;
}
bool check1(int c,int d,int vd,int va)
{
build();
rec[0]=tot; rec[1]=point[A]; rec[2]=point[B];
rec[3]=point[c]; rec[4]=point[d]; rec[5]=point[0];
int t=vd-va-1;
add(c,B,t);
add(0,d,vd); add(d,0,-vd);
add(0,A,va); add(A,0,-va);
spfa(0);
tot=rec[0]; point[A]=rec[1]; point[B]=rec[2];
point[c]=rec[3]; point[d]=rec[4]; point[0]=rec[5];
return pd;
}
bool check2(int c,int d,int vd,int va)
{
build();
rec[0]=tot; rec[1]=point[A]; rec[2]=point[B];
rec[3]=point[c]; rec[4]=point[d]; rec[5]=point[0];
int t=va-vd-1;
add(B,c,t);
add(0,d,vd); add(d,0,-vd);
add(0,A,va); add(A,0,-va);
spfa(0);
tot=rec[0]; point[A]=rec[1]; point[B]=rec[2];
point[c]=rec[3]; point[d]=rec[4]; point[0]=rec[5];
return pd;
}
bool check3(int c,int d,int vd,int va)
{
build();
rec[0]=tot; rec[1]=point[A]; rec[2]=point[B];
rec[3]=point[c]; rec[4]=point[d]; rec[5]=point[0];
int t=vd-va;
add(c,B,t); add(B,c,-t);
add(0,d,vd); add(d,0,-vd);
add(0,A,va); add(A,0,-va);
spfa(0);
tot=rec[0]; point[A]=rec[1]; point[B]=rec[2];
point[c]=rec[3]; point[d]=rec[4]; point[0]=rec[5];
return pd;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d%d",&n,&A,&B);
for (int i=1;i<=n;i++) {
char s[100]; scanf("%s",s+1);
for (int j=1;j<=n;j++){
if (s[j]=='+') add(i,j,-1);
if (s[j]=='-') add(j,i,-1);
if (s[j]=='=') add(j,i,0),add(i,j,0);
}
}
for (int i=1;i<=n;i++) add(0,i,3),add(i,0,-1);
for (int i=1;i<n;i++)
for(int j=i+1;j<=n;j++) {
if (i==A||j==B||i==B||j==A) continue;
int v1=0,v2=0,v3=0;
for (int d=1;d<=3;d++){
for (int a=1;a<=3;a++) {
int t1=check1(i,j,d,a);
int t2=check2(i,j,d,a);
int t3=check3(i,j,d,a);
if (!t1) v1++;
if (!t2) v2++;
if (!t3) v3++;
}
}
if (v1&&!v2&&!v3) ans[1]++;
if (!v1&&v2&&!v3) ans[2]++;
if (!v1&&!v2&&v3) ans[3]++;
}
printf("%d %d %d\n",ans[2],ans[3],ans[1]);
}