BZOJ 1077: [SCOI2008]天平

題面

題意

有n個砝碼,每個砝碼的質量爲1g,2g或3g,但你不知道每個砝碼的具體質量是多少,但你知道它們某幾對砝碼之間的大小關係,先將兩個砝碼A,B放在天平左邊,請你再選兩個砝碼放在天平右邊,求有多少種選法使得天平的左邊重、一樣重、右邊重?(只有結果保證惟一的選法才統計在內)

做法

我們可以將A+BA+BC+DC+D的大小關係轉化爲ACA-CDBD-B的關係或是ADA-DCBC-B的關係,而若ii砝碼比jj砝碼重,則可以轉化爲1<=m[i]m[j]<=21<=m[i]-m[j]<=2,而ii砝碼比jj砝碼輕也是同理,如果不知道ii砝碼與jj砝碼的關係,那麼2<=m[i]m[j]<=2-2<=m[i]-m[j]<=2,因此此題就可以轉化爲給出幾個不等式,求解另外幾個不等式,可以用差分約束系統來解決,對於每個差的上限用最短路來解,每個差的下限用最長路來解,然後判斷每對CCDD是否一定滿足即可。
需要注意的是ACDB(A-C,D-B)ADCB(A-D,C-B)兩種轉化方式中,只要有一種轉化方式的結果是唯一的,那麼這對CCDD就是合法的,因此判斷時需要比較兩種不等式的值。

代碼

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章