UVA10651(狀態壓縮)

題目

題目可以看這裏 洛谷
但洛谷提交需要綁定私人賬號,大部分人應該沒有,所以可以用VJ提交,但VJ看不到題面,所以可以題面看洛谷,提交用VJ
題目提交看這裏 Virtual Judge

題解

開始做狀態壓縮的題了,逐漸明白了狀態壓縮的本質就是爆搜,真的就是遍歷所有的情況,至於爲什麼要用2進制進行存儲狀態我的理解是方便修改,而且方便給每一種情況編號,如果是三選問題或者四選甚至更多的話就不能用狀態壓縮了,最明顯的標誌就是位數在10位左右,因爲狀態的數量級呈指數增長

提醒:請給所有的 1<<i 加一個括號,WA到哭了,還有邏輯非是!,按位非是~,符號不一樣的啊!!!,WA到懷疑人生

這題就是從給出的棋盤開始,有棋子爲1,沒有爲0,將給出的棋盤入隊,找是否有兩個1相連的情況,如果有,再判斷左邊是否有1,沒有入隊,再判斷右邊,沒有入隊,重複以上操作,因爲每次操作完棋子會少一個,所以貪心的認爲一定是最後一個出隊的棋盤情況有最少的棋子數,輸出最後一個棋盤的棋子數即可

特殊情況是最後兩位的1,和最前頭兩位的1,不能向右/向左延伸,可以增加兩個if進行特判,但也有個小技巧就是給第0列,第13列(不存在的兩列)賦1,這樣就不需要特判了,因爲有1限制就一定無法向外移動
(小錯誤WA了半天,添加了很多輸出判斷的語句,懶得刪了)

#include<iostream>
#include<queue>
using namespace std;
queue<int> q;
int qi,dp[15],cnt;
void init()
{
	for(int i=1;i<=11;i++){
		dp[i]=(1<<i)+(1<<(i+1));
	}
}
void duru()
{
	char m;getchar();qi=0;
	for(int i=12;i>=1;i--){
		scanf("%c",&m);
		if(m=='o') qi+=(1<<i);
	}
	qi+=(1<<0)+(1<<13);
	q.push(qi);
}
void update(int x,int i)
{
	int l=i-1,r=i+2,y=x;
	if((x&(1<<l))==0){
		//cout<<"l:"<<l<<endl;
		y=(y&(~dp[i]));
		//cout<<y<<endl;
		y+=(1<<l);
		q.push(y);
	}
	y=x;
	if((x&(1<<r))==0){
		//cout<<"r:"<<r<<endl;
		y=(y&(~dp[i]));
		//cout<<y<<endl;
		y+=(1<<r);
		q.push(y);
	}
}
int jisuan(int x)
{
	int tot=0;
	for(int i=12;i>=1;i--){
		if(x&(1<<i)) tot++;
	}
	return tot;
}
int main()
{
	int n,x;
	cin>>n;
	init();
	for(int i=1;i<=n;i++){
		duru();
		//cout<<qi<<endl;
		while(q.size()){
			x=q.front();q.pop();//cout<<x<<endl;
			for(int i=1;i<=11;i++){
				if((dp[i]&x)==dp[i]){
					//cout<<"i:"<<i<<' '<<(dp[i]&x)<<' '<<dp[i]<<endl;
					update(x,i);
				}
			}
		}
		cout<<jisuan(x)<<endl;
	}
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章