總結&&up
(因人而異,這只是我個人的)
- 對於的下次遞歸別亂放,否則容易。
- 由於要入隊,所以要記憶化(否則可能會超內存),
防止一個位置重複入隊
1.棋盤問題(類似8皇后問題:)
題意:
有一個棋盤,只能在‘#’裏放棋子,保證行列不衝突,問有幾種方法。
思路:
- 用一個棋子數組,標記所放棋子的列號,保證列不衝突。
- 暴力枚舉第行 的每一列是否能放棋子,(當前行,可以放也可以不放)
- 放了k個就停止。
反思:
對於的下次遞歸別亂放,否則容易。
AC
#include <iostream>
#include <cstring>
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(int i=(x); i<=(y); i++)
using namespace std;
int g[10][10],a[10];
int n,k;
string s;
int dfs(int cur, int tot)
{
int ans=0;
if(tot==k)return 1;
if(cur>n)return 0;//
For(i,1,n)
{
if(!a[i]&&g[cur][i]==1)
{
a[i]=1;
ans+=dfs(cur+1,tot+1);
a[i]=0;
//ans+=dfs(cur+1,tot);///一開始放錯位置了,導致tle
}
}
ans+=dfs(cur+1,tot);//應該放在這裏,因爲當前行不放,那麼就不用進for循環裏
return ans;
}
int main()
{
while(cin>>n>>k&&(n!=-1&&k!=-1))
{
mst(g,0);
For(i,1,n)
{
cin>>s;
a[i]=0;
for(int j=0; j<s.size(); j++)if(s[j]=='#')g[i][j+1]=1;
}
cout<<dfs(1,0)<<endl;
}
return 0;
}
2.POJ 2251 Dungeon Master(三維走迷宮,)
題意:
有一個三維迷宮,問是否能走出。如果能走出輸出最短路,否則輸出“IMPOSSIBLE”.
思路:
- 由於三維,所以方向多加一個
上下
即可,變成六個方向的 - 由於要最短路,邊權爲1,所以直接跑。
AC
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#define mp make_pair
#define mst(x,a) memset(x,a,sizeof(x))
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
int flag=0;
int g[40][40][40];
int l,r,c;
int dx[6]={0,0,0,0,-1,1};
int dy[6]={0,0,1,-1,0,0};
int dz[6]={1,-1,0,0,0,0};
int ls,xs,ys,le,xe,ye;
int ans=0;
struct point{int x,y,z,dis;};
void bfs(int z, int x, int y)
{
point fi={x,y,z,0};//定義結構體時,注意變量的賦值順序,吐了qwq。
g[z][x][y]=1;
queue<point>q;
q.push(fi);
while(!q.empty())
{
point top=q.front();q.pop();
z=top.z,x=top.x;y=top.y;
//cout<<z<<' '<<x<<' '<<y<<endl;
//cout<<g[z][x][y]<<endl;
int dis=top.dis;
if(z==le&&xe==x&&y==ye)
{
ans=dis;
flag=1;return;
}
For(i,0,5)
{
int tx,ty,tz;
tx=x+dx[i];
ty=y+dy[i];
tz=z+dz[i];
if(tz>=1&&tz<=l&&ty<=c&&ty>=1&&tx>=1&&tx<=r&&!g[tz][tx][ty])
{
//cout<<tz<<' '<<tx<<' '<<ty<<endl;
// cout<<g[tz][tx][ty]<<endl;
g[tz][tx][ty]=1;
q.push({tx,ty,tz,dis+1});
}
}
}
}
int main()
{
while(cin>>l>>r>>c&&(l|r|c))
{
mst(g,0);flag=0;
string s[40];
For(i,1,l)
{
For(j,1,r)cin>>s[j];
//getchar();
For(j,1,r)
{
For(k,0,c-1)
{
if(s[j][k]=='S')xs=j,ys=k+1,ls=i;
if(s[j][k]=='E')xe=j,ye=k+1,le=i;
if(s[j][k]=='#')g[i][j][k+1]=1;
}
}
}
bfs(ls,xs,ys);
if(flag)cout<<"Escaped in "<<ans<<" minute(s)."<<endl;
else cout<<"Trapped!"<<endl;
}
return 0;
}
3.POJ 3278 Catch That Cow(經典)
題意:
給你農夫的位置和牛的位置,問你農夫最少用多少時間可以抓到牛。
農夫每一步有三種op:
思路:
由於是每步操作,有層次,所以跑。
反思:
由於要入隊,所以要記憶化(否則可能會超內存),防止一個位置重複入隊
AC
#include <iostream>
#include <queue>
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef pair<int,int>pa;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
queue<pa>q;
int vis[maxn];//注意記憶化,已經入隊的元素,就不要重複入隊了。否則會爆內存。
int main()
{
int n,k,ans=0;
cin>>n>>k;
vis[n]=1;
q.push(mp(n,0));
while(!q.empty())
{
int x=q.front().fi,time=q.front().se; q.pop();
if(x==k){ans=time;break;}
if(x+1<=maxn-1&&!vis[x+1])vis[x+1]=1,q.push(mp(x+1,time+1));
if(x-1>=0&&!vis[x-1])vis[x-1]=1,q.push(mp(x-1,time+1));
if(x*2<=maxn-1&&!vis[x*2])vis[x*2]=1,q.push(mp(x*2,time+1));
}
cout<<ans<<endl;
return 0;
}
4.POJ 3279 Fliptile(經典棋盤翻轉問題|開燈問題)
題意:
給你一個矩陣,每個小格有一塊瓦,瓦有黑白兩色。
每一次翻轉,都會使相鄰的也翻轉。
求字典序最小的翻轉。
思路:
- 可以枚舉第一行的switch(總共最多)而col最大也15,所以放心枚舉。
- 之後就和掃雷差不多了,有了前面的基礎,去推後面的。
- 根據switch去改變第一行的顏色。第一行剩下的沒變白的,由下一行改變,
- 操作結束後,最後看最後一行是否變白。
反思
- 把一個數的某一位(二進制)變爲1:
- 把一個數的某一位(二進制)變爲0: &=~(1<<)
- 把一個數的某一位(二進制)取反: ^=1<<
- 找到一個數的某一位(二進制): (>>)&1
- 數組的複製。memcpy(light,orlight,sizeof(orlight))
AC
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int orlight[30];
int a,n,m;
//char s[10];
int light[30];
int result[30];//int is 4bits ,but char is 1 bit.
//if the data is 1<<8,we can just use char to store the data.
//other else ,we must use int or long long in instead.
int get_bit(int c,int i){return (c>>i)&1;}
void change(int bit, int t)
{
if(a)orlight[t]|=(1<<bit);
else orlight[t] &= ~(1<<bit);
}
void init()
{
memset(orlight,0,sizeof(orlight));
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
cin>>a;
change(j,i);
}
// cout<<(int)orlight[i]<<endl;
}
}
void turnlight(int &x, int pos)
{
x^=1<<pos;
}
/*
void copy_light()
{
for(int i=0; i<n; i++)light[i]=orlight[i];
}
*/
void revers(int t)
{
for(int i=0; i<m; i++)
{
//if(i!=m-1)
cout<<get_bit(result[t],i)<<' ';
// cout<<((result[t]>>i)&1)<<" ";ok
//cout<<((result[t]&(1<<i))>>i)<<" ";no
// else
//cout<<((result[t]>>i)&1)<<endl;
}
cout<<endl;
}
void solve()
{
int switch_num=0;
bool flag=0;
for(int i=0; i<(1<<m); i++)
{
if(flag)break;
//copy_light();
memcpy(light,orlight,sizeof(orlight));//!!!!!!!
switch_num=i;
for(int j=0; j<n; j++)
{
result[j]=switch_num;
for(int k=0; k<m; k++)
{
if((switch_num&(1<<k)))
{
turnlight(light[j],k);//light[j]^=1<<k;
if(k>0)turnlight(light[j],k-1);
if(k+1<m)turnlight(light[j], k+1);
}
}
if(j+1<n)light[j+1]^=switch_num;
switch_num=light[j];//if(j==n-1&&light[j]==0)flag=1;
}
if(light[n-1]==0)flag=1;
}
if(flag)for(int i=0; i<n; i++)revers(i);
else cout<<"IMPOSSIBLE"<<endl;
}
int main()
{
while(cin>>n>>m)
{
init();
solve();
}
return 0;
}
/*
bool check()
{
for(int i=0; i<5; i++)if(light[i]!=0)return false;
return true;
}
int getbit(int num, int bit)
{
return
}
*/
5.POJ 1426 Find The Multiple(經典和同餘)
題意:
給你一個數n,要你找到它的一個倍數m,m只能由1,0組成。
思路:
- 對於m的最高位肯定是1.
- 之後就跑bfs。看隊首元素是否滿足front%n=0
- 不滿足,就對m*10,之後把新的m和m+1入隊.
- 由於是大數,所以用同餘優化一下。
- 而答案可以通過記錄操作數來取得。(操作就是*10,之後+0或者+1)
AC
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,cnt;
while(cin>>n&&n)
{
cnt=0;
vector<int>ans;
queue<int>q;q.push(1);
while(!q.empty())
{
int top=q.front(); q.pop();
cnt++;//統計總共進行了幾次操作。
if(top%n==0)break;
q.push( (top%n*(10%n))%n );
q.push( (top%n*(10%n))%n+1 );
}
/// bfs隊列常見技巧,根據總操作數,逆堆。
for(int i=cnt; i; i/=2)ans.push_back(i%2);
//由於每次操作不是加0就是1,所以可以根據總操作數,來逆推出答案
for(int i=ans.size()-1; i>=0; i--)cout<<ans[i];
cout<<endl;
}
return 0;
}