題目
題目可以看這裏 洛谷
但洛谷提交需要綁定私人賬號,大部分人應該沒有,所以可以用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;
}
}