/*
POJ 1979 模板题目
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
int W,H;
char dict[22][22];
int sum;
bool check(int x,int y){
if(!(x>=1&&x<=H&&y>=1&&y<=W))
return false;
return true;
}
void dfs(int x,int y){
if(!check(x,y))
return ;
if(dict[x][y]=='.'||dict[x][y]=='@'){
sum++;
dict[x][y]='#';
dfs(x,y-1);
dfs(x-1,y);
dfs(x,y+1);
dfs(x+1,y);
}
}
int main(){
int start_x,start_y;
while(~scanf("%d%d",&W,&H)){
if(W==H && W==0)
break;
for(int i=1;i<=H;i++){
getchar();
for(int j=1;j<=W;j++){
scanf("%c",&dict[i][j]);
if(dict[i][j]=='@'){
start_x=i;
start_y=j;
}
}
}
sum=0;
dfs(start_x,start_y);
printf("%d\n",sum);
}
}
/*
经典DFS()
POJ 3009
*/
#include<cstdio>
#include<cstring>
int w,h;//记录场地的宽和高
int sx,sy,ex,ey;//记录起点和终点坐标
int d[4][2] = { {0,-1}, {1,0}, {0,1}, {-1,0} };//存方向变化量
int dict[30][30],best;//best记录最优解。dict存地图
void dfs(int cx,int cy,int step){//cx,cy记录当前位置。step表示已走多少步
int nx,ny;
if(step>best)//剪枝如果大于目前最优解直接返回
return;
for(int i=0;i<4;i++){
nx=cx+d[i][0];
ny=cy+d[i][1];
if(nx>=h||nx<0||ny<0||ny>=w||dict[nx][ny]==1)//越界或立即有阻挡物剪枝
continue;
while(nx<h&&nx>=0&&ny<w&&ny>=0&&dict[nx][ny]!=1){//一直滑
if(nx==ex&&ny==ey){//若到终点
if(step+1<best)
best=step+1;
break;
}
nx+=d[i][0];
ny+=d[i][1];
}
if(nx==ex&&ny==ey)//若由于到终点跳出去
continue;
if(nx<h&&nx>=0&&ny<w&&ny>=0){
dict[nx][ny]=0;//若是碰到阻挡物。阻挡物消失。
dfs(nx-d[i][0],ny-d[i][1],step+1);//继续搜索
dict[nx][ny]=1;//还原阻挡物。回溯
}
}
}
int main(){
while(scanf("%d%d",&w,&h),w||h){
best=12;//初始化best
for(int i=0;i<h;i++)//读取地图
for(int j=0;j<w;j++){
scanf("%d",&dict[i][j]);
if(dict[i][j]==2){
sx=i;
sy=j;
}
if(dict[i][j]==3){
ex=i;
ey=j;
}
}
dfs(sx,sy,0);//深搜
if(best<=10)
printf("%d\n",best);
else
printf("-1\n");
}
}
详细代码
http://blog.csdn.net/bossup/article/details/9014701
/*
经典BFS()
POJ 3669
*/
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
typedef pair<int ,int >P;
const int MAX_M=50000;
const int MAX_N=400+1;
const int INF=0x7fffffff;
//输入
int M;
int X[MAX_M],Y[MAX_M],T[MAX_M];
int dict[MAX_N][MAX_N];//保存地图
int d[MAX_N][MAX_N];//保存最短步数
int z[4][2] = { {0,-1}, {1,0}, {0,1}, {-1,0} };
int bfs(){
if(dict[0][0]==0) return -1; //一开始就被炸
queue<P>que;
que.push(P(0,0));
d[0][0]=0;
while(!que.empty()){
P p=que.front();
que.pop();
//已到达安全位置
int x=p.first,y=p.second;
if(dict[x][y]==INF) return d[x][y];
//4个方向走
for(int i=0;i<4;i++){
int nx=x+z[i][0];
int ny=y+z[i][1];
//判断是否可移动,是否访问过,以及下一个时刻是否安全
if(nx>=0&&ny>=0&&d[nx][ny]==INF&&d[x][y]+1<dict[nx][ny]){
que.push(P(nx,ny));
d[nx][ny]=d[x][y]+1;
}
}
}
return -1;
}
int solve(){
//初始化地图
for(int i=0;i<MAX_N;i++)
fill(dict[i],dict[i]+MAX_N,INF);
//模拟轰炸场景
for(int i=0;i<M;i++){
dict[X[i]][Y[i]]=min(dict[X[i]][Y[i]],T[i]);
for(int j=0;j<4;j++){
int nx=X[i]+z[j][0];
int ny=Y[i]+z[j][1];
if(nx>=0&&ny>=0)
dict[nx][ny]=min(dict[nx][ny],T[i]);
}
}
//初始化地图最小步数
for(int i=0;i<MAX_N;i++)
fill(d[i],d[i]+MAX_N,INF);
//宽度优先搜索
int ans=bfs();
printf("%d\n",ans);
}
int main(){
scanf("%d",&M);
for(int i=0;i<M;i++)
scanf("%d %d %d",&X[i],&Y[i],&T[i]);
solve();
}
详细代码
http://www.cnblogs.com/7hat/p/3595630.html
/*
POJ 3187
题意:已知有N个数分别为1-N,如下图为4个数。相邻两两相加直至只剩下一个数,下图的结果就是16。
3 1 2 4
4 3 6
7 9
16
现在反过来看,告诉你数的个数N和最终结果,问这N个数的初始序列是什么。求出字典序最小的初始序列。上图的初始序列也可以是3 2 1 4,但这不是字典序最小。
分析:这题用全排列的方式非常容易做。首先初始化数组为1-N,然后用STL提供的按字典序生成全排列的函数next_permutation即可枚举全排列。对于每一组数,通过计算可以知道它是否能得出已知结果。最先找到的那组数就是字典序最小的值。
*/
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_N=10;
int N,finalsum;
int a[MAX_N][MAX_N];
int calulate(){//计算序列所得的最后和
for(int i=1;i<N;i++){
for(int j=0;j<N-i;j++){
a[i][j]=a[i-1][j]+a[i-1][j+1];
}
}
return a[N-1][0];
}
void solve(){
for(int i=0;i<N;i++)//初始化序列
a[0][i]=i+1;
do{//按字典序枚举全排列
int sum=calulate();
if(sum==finalsum){
printf("%d",a[0][0]);
for(int i=1;i<N;i++)
printf(" %d",a[0][i]);
printf("\n");
break;
}
}while(next_permutation(a[0],a[0]+N));
}
int main(){
scanf("%d %d",&N,&finalsum);
solve();
return 0;
}
/*
题意:给定一个5*5的地图,每个格子上有一个数字。从一个格子出发(上下左右4个方向),走5步将数字连起来可以构造出一个6位数。问该地图可以构造出多少个不同的6位数。
分析:可以对每个格子做深度优先遍历,构造出所有数字,但要注意不要重复计数。在这里,我使用了set来保存已构造出的数字,结果就是set中的元素个数。
POJ 3050
*/
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
int dict[5][5];
set<int>st;
int d[4][2] = { {0,-1}, {1,0}, {0,1}, {-1,0} };
int dfs(int x,int y,int k,int num){
if(k==6){
st.insert(num);
return 0;
}
for(int i=0;i<4;i++){
int nx=x+d[i][0];
int ny=y+d[i][1];
if(nx>=0&&nx<5&&ny>=0&&ny<5){
k++;
dfs(nx,ny,k,num*10+dict[nx][ny]);
k--;//回溯
}
}
}
void solve(){
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
dfs(i,j,1,dict[i][j]);
printf("%d\n",st.size());
}
int main(){
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
scanf("%d",&dict[i][j]);
solve();
}
/*
部分和问题
NYOJ 927
*/
#include<cstdio>
int a[25];
int n,k;
bool dfs(int i,int sum){
if(i==n)
return sum==k;
if(dfs(i+1,sum)) return true;
if(dfs(i+1,sum+a[i])) return true;
return false;
}
int main(){
while(~scanf("%d",&n)){
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
scanf("%d",&k);
if(dfs(0,0))
printf("Of course,I can!\n");
else
printf("Sorry,I can't!\n");
}
}
/*
深搜或者广搜
保存上一节点即可
NYOJ 20
*/
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int MAXN=100010;
vector<int>Graph[MAXN];
int preNode[MAXN];
void DFS(int CurNode){
for(int i=0;i<Graph[CurNode].size();i++){
if(preNode[Graph[CurNode][i]])//如果当前节点已经访问过,那么就继续搜索CurNode的下一个邻接点
continue;
preNode[Graph[CurNode][i]]=CurNode;
DFS(Graph[CurNode][i]);
}
}
void BFS(int CurNode){
int que[MAXN],qs,qe;
memset(que,0,sizeof(que));
qe=qs=0;
que[qe++]=CurNode;
while(qs<qe){
int u=que[qs++];
for(int i=0;i<Graph[u].size();i++){
if(preNode[Graph[u][i]])
continue;
preNode[Graph[u][i]]=u;
que[qe++]=Graph[u][i];
}
}
}
int main(){
int test;
int n,start;
int a,b;
scanf("%d",&test);
while(test--){
scanf("%d%d",&n,&start);
memset(Graph,0,sizeof(Graph));
memset(preNode,0,sizeof(preNode));
for(int i=0;i<n-1;i++){
scanf("%d%d",&a,&b);
Graph[a].push_back(b);//只要相邻就添加双向边
Graph[b].push_back(a);
}
preNode[start]=-1;
DFS(start);
for(int i=1;i<=n;i++)
printf("%d ",preNode[i]);
}
}
/*
连连看
HDU 1175
*/
#include<cstdio>
#include<queue>
using namespace std;
#define INT_MAX 0x3f3f3f3f
int direc[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//方向依次为右、左、下、上
int dict[1005][1005],vis[1005][1005],m,n;
//a为输入的2维向量,visited记录该点是否被访问过了,同时记录有转折次数,如果
//新的转折次数小于以前访问时的转折次数那么更新,否则就不更新。
typedef struct {
int x,y,dir,corner;//x,y,为行数列数,dir为方向,corner为转角次数。
}node;
node start,endx;
void bfs(){
queue<node>q;
node cur,pre;//用来记录当前的节点和前一个进行比较
start.dir=-1;//开始时无方向
start.corner=0;//开始时转角次数为0
q.push(start);
while(!q.empty()){
pre=q.front();
q.pop();
if(pre.x==endx.x&&pre.y==endx.y){
printf("YES\n");
return ;
}
for(int i=0;i<4;i++){//对节点的四个方向分别进行判断
cur.x=pre.x+direc[i][0];
cur.y=pre.y+direc[i][1];
cur.corner=pre.corner; //令当前转角次数和前一个相同
cur.dir=i;
//当前方向
//前一个不能使开始出,且当前方向和前一个方向不一致是转折次数自增1
if(pre.dir!=cur.dir&&pre.dir!=-1) cur.corner++;
//判断是否出界,转角次数是否超过限制
if(cur.x<1||cur.y<1||cur.x>n||cur.y>m||cur.corner>2) continue;
//如果当前位置有数字存在,且当前位置不是终结位置,违反规则
if(dict[cur.x][cur.y]&&!(cur.x==endx.x&&cur.y==endx.y)) continue;
if(cur.corner<vis[cur.x][cur.y]){
vis[cur.x][cur.y]=cur.corner;
q.push(cur);
}
}
}
printf("NO\n");
}
int main(){
int q;
while(~scanf("%d%d",&n,&m),n,m){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&dict[i][j]);
scanf("%d",&q);
while(q--){
scanf("%d%d%d%d",&start.x,&start.y,&endx.x,&endx.y);
if(start.x==endx.x&&start.y==endx.y) {printf("NO\n"); continue;} //开始和结束在同一个位置
//开始和结束位置没有数字或者开始和结束位置的数字不等。
if(!dict[start.x][start.y]||!dict[endx.x][endx.y]||(dict[start.x][start.y]!=dict[endx.x][endx.y])) {printf("NO\n"); continue;}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
vis[i][j]=INT_MAX;
bfs();
}
}
}