BZOJ 1077: [SCOI2008]天平

题面

题意

有n个砝码,每个砝码的质量为1g,2g或3g,但你不知道每个砝码的具体质量是多少,但你知道它们某几对砝码之间的大小关系,先将两个砝码A,B放在天平左边,请你再选两个砝码放在天平右边,求有多少种选法使得天平的左边重、一样重、右边重?(只有结果保证惟一的选法才统计在内)

做法

我们可以将 A + B A+B A+B C + D C+D C+D的大小关系转化为 A − C A-C AC D − B D-B DB的关系或是 A − D A-D AD C − B C-B CB的关系,而若 i i i砝码比 j j j砝码重,则可以转化为 1 &lt; = m [ i ] − m [ j ] &lt; = 2 1&lt;=m[i]-m[j]&lt;=2 1<=m[i]m[j]<=2,而 i i i砝码比 j j j砝码轻也是同理,如果不知道 i i i砝码与 j j j砝码的关系,那么 − 2 &lt; = m [ i ] − m [ j ] &lt; = 2 -2&lt;=m[i]-m[j]&lt;=2 2<=m[i]m[j]<=2,因此此题就可以转化为给出几个不等式,求解另外几个不等式,可以用差分约束系统来解决,对于每个差的上限用最短路来解,每个差的下限用最长路来解,然后判断每对 C C C D D D是否一定满足即可。
需要注意的是 ( A − C , D − B ) (A-C,D-B) ACDB ( A − D , C − B ) (A-D,C-B) ADCB两种转化方式中,只要有一种转化方式的结果是唯一的,那么这对 C C C D D D就是合法的,因此判断时需要比较两种不等式的值。

代码

#include<iostream>
#include<cstdio>
#define N 60
using namespace std;

int n,A,B,mx[N][N],mn[N][N],c1,c2,c3,ans;
char str[N];

int main()
{
	int i,j,k;
	cin>>n>>A>>B;
	for(i=1;i<=n;i++)
	{
		scanf("%s",str+1);
		str[i]='=';
		for(j=1;j<=n;j++)
		{
			if(str[j]=='+') mx[j][i]=2,mn[j][i]=1;
			else if(str[j]=='-') mx[j][i]=-1,mn[j][i]=-2;
			else if(str[j]=='?') mx[j][i]=2,mn[j][i]=-2;
			else if(str[j]=='=') mx[j][i]=mn[j][i]=0;
		}
	}
	for(k=1;k<=n;k++)
	{
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				mx[i][j]=min(mx[i][j],mx[i][k]+mx[k][j]);
				mn[i][j]=max(mn[i][j],mn[i][k]+mn[k][j]);
			}
		}
	}
	for(i=1;i<=n;i++)
	{
		if(i==A || i==B) continue;
		for(j=i+1;j<=n;j++)
		{
			if(j==A || j==B) continue;
			if(mx[i][A]<mn[B][j] || mx[j][A]<mn[B][i]) c3++;
			else if(mn[i][A]>mx[B][j] || mn[j][A]>mx[B][i]) c1++;
			else if(mx[i][A]==mn[i][A]&&mx[B][j]==mn[B][j]&&mx[i][A]==mx[B][j] || mx[j][A]==mn[j][A]&&mx[B][i]==mn[B][i]&&mx[j][A]==mx[B][i]) c2++;
		}
	}
	cout<<c1<<" "<<c2<<" "<<c3;
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页