UVA1607 Gates

這種題目。。。哎。。智商不夠用啊。。由於輸入只有一個x的值,所以電路無論多複雜,最終結果只有1,0,x或!x(所以可以這樣理解,當電路的輸出與x相關時,原電路一定可以等效爲輸入序列只有一個x其餘均爲0/1的情況)。取x爲0與x爲1,如果電路的輸出結果相同,那麼電路的輸出結果一定是常數,那麼隨便輸出一串0,1就行。。否則,由前面的討論我們只需要找到那個填上x的位置,從全爲0的輸入開始,對於全爲0的輸入記其輸出爲a。每次將輸入序列的第一個0替換爲1。直到找到一個k使得輸入序列的前k個數均爲1時,該序列的輸出結果不是a爲止,那麼我們的輸入序列可以簡化爲111...1(k-1個1)x00000...(後面全是0)。因爲對於全爲1的輸入序列,其輸出不等於a所以符合條件的k一定存在,即這樣的算法一定會給出答案。關於k的找法用二分,詳見代碼。

AC代碼如下:(參考了編程。。畢竟我真的不會寫這題。。)


#include <cstdio>

using namespace std;

int n,m,inp1[200005],inp2[200005],out[2000005];

int calculate(int k)               //當輸入序列的前k個數均爲1時求電路的輸出
{
	for(int i=1;i<=m;i++)
	{
		int a,b;
		if(inp1[i]<0)
			a=(-inp1[i]<=k);
		else
			a=out[inp1[i]];
		if(inp2[i]<0)
			b=(-inp2[i]<=k);
		else
			b=out[inp2[i]];
		out[i]=!(a&b);
	}
	return out[m];
}

int main(int argc, char const *argv[])
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d %d", &n, &m);
		for(int i=1;i<=m;i++)
			scanf("%d %d", &inp1[i],&inp2[i]);
		int x,y;
		x=calculate(0);
		y=calculate(n);
		if(x==y)
		{
			for(int i=1;i<=n;i++)
				printf("0");
				printf("\n");
		}
		else
		{
			int L=0,R=n,mid=1;              //二分查找
			while(R-L>1)
			{
				mid=(L+R)/2;
				if(calculate(mid)==x)
					L=mid;
				else
					R=mid;
			}
			for(int i=1;i<=n;i++)
			{
				if(i<R) printf("1");
				else if(i==R) printf("x");
				else printf("0");
			}
			printf("\n");
		}
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章