题解
这道题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<bits/stdc++.h> const int N=100003; using namespace std; int tot,ne[N],fi[N],zz[N],c[N],mp[103][103],ans[5]; int can[N],dis[N],n,B,A,rec[10],pd; void add(int x,int y,int z) { tot++; ne[tot]=fi[x]; fi[x]=tot; zz[tot]=y; c[tot]=z; } void spfa(int x) { can[x]=1; for (int i=fi[x];i;i=ne[i]) if (dis[zz[i]]>dis[x]+c[i]) { dis[zz[i]]=dis[x]+c[i]; if (can[zz[i]]) { pd=1; return; } spfa(zz[i]); if (pd) return; } can[x]=0; } void build() { pd=0; for (int i=0;i<=n;i++) dis[i]=1e9,can[i]=0; dis[0]=0; } int check1(int c,int d,int vd,int va) { build(); rec[0]=tot; rec[1]=fi[A]; rec[2]=fi[B]; rec[3]=fi[c]; rec[4]=fi[d]; rec[5]=fi[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]; fi[A]=rec[1]; fi[B]=rec[2]; fi[c]=rec[3]; fi[d]=rec[4]; fi[0]=rec[5]; return pd; } int check2(int c,int d,int vd,int va) { build(); rec[0]=tot; rec[1]=fi[A]; rec[2]=fi[B]; rec[3]=fi[c]; rec[4]=fi[d]; rec[5]=fi[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]; fi[A]=rec[1]; fi[B]=rec[2]; fi[c]=rec[3]; fi[d]=rec[4]; fi[0]=rec[5]; return pd; } int check3(int c,int d,int vd,int va) { build(); rec[0]=tot; rec[1]=fi[A]; rec[2]=fi[B]; rec[3]=fi[c]; rec[4]=fi[d]; rec[5]=fi[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]; fi[A]=rec[1]; fi[B]=rec[2]; fi[c]=rec[3]; fi[d]=rec[4]; fi[0]=rec[5]; return pd; } int main() { 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]); }