搜索專題

  1. 廣度搜索
優點:
目標節點如果存在,用寬度優先搜索算法總可以找到該目標節點,而且是最小(即最短路徑)的節點.
缺點:
當目標節點距離初始節點較遠時,會產生許多無用的節點,搜索效率低.

例題:

poj  3278  Catch That Cow

#include <iostream>
#include <queue>
using namespace std;

#define MAXN 100010
int n,k;
int dis[MAXN];			//步驟數

int bfs(){
    memset(dis,-1,sizeof(dis));		//表示未用過 
    queue<int>q;
    q.push(n);
    dis[n]=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        if(x==k){return dis[x];}
        if(x+1>=0 && dis[x+1]==-1){
            q.push(x+1);
            dis[x+1]=dis[x]+1;
        }
        if(x-1>=0 && dis[x-1]==-1){
            q.push(x-1);
            dis[x-1]=dis[x]+1;
        }
        if(x*2<MAXN && dis[x*2]==-1){
            q.push(x*2);
            dis[x*2]=dis[x]+1;
        }
    }
    return -1; 
}

int main(){
    while(cin>>n>>k)
        cout<<bfs()<<endl;
    return 0;
}


hdu 1026 Ignatius and the Princess I

優先隊列+BFS

#include <iostream>
#include <queue>
using namespace std;

#define  INF 1<<31-1;
int n,m;
char graph[101][101];
int dis[101][101];
int dir[4][2]={-1,0,0,1,1,0,0,-1};

struct point{
    int x,y,time;
    bool operator <(const point b)const{
		return time>b.time;
    }
}begin,end,cur,path[101][101],neighbor;

int bfs(){
    begin.x=0,begin.y=0;begin.time=0;
    dis[0][0]=0;
    priority_queue<point>q;
    q.push(begin);
    while(!q.empty()){
        cur=q.top();q.pop();
        if(cur.x==n-1&&cur.y==m-1){
            end=cur;
            return cur.time;
        }
        for(int i=0;i<4;i++){
            neighbor.x=cur.x+dir[i][0];
            neighbor.y=cur.y+dir[i][1];
            if(neighbor.x>=0&&neighbor.x<n&&neighbor.y>=0&&neighbor.y<m&&graph[neighbor.x][neighbor.y]!='X'){
                if(graph[neighbor.x][neighbor.y]=='.'){
                    neighbor.time=cur.time+1;
                } 
                else neighbor.time=cur.time+graph[neighbor.x][neighbor.y]-'0'+1;
                if(neighbor.time<dis[neighbor.x][neighbor.y]){
                    dis[neighbor.x][neighbor.y]=neighbor.time;
                    path[neighbor.x][neighbor.y]=cur;
                    q.push(neighbor);
                }
            }
        }
    }
    return -1;
}
int getpath(point next){//遞歸輸出路徑
    int t=1,s;
    point pre;
    if(next.x==0&&next.y==0)
        return 0;
    pre=path[next.x][next.y];
    t+=getpath(pre);
    printf("%ds:(%d,%d)->(%d,%d)\n",t,pre.x,pre.y,next.x,next.y);

    //FIGHTing...
    if(graph[next.x][next.y]>='0'&&graph[next.x][next.y]<='9'){
        s=graph[next.x][next.y]-'0';
        for(int i=t+1;i<=t+s;i++){
            printf("%ds:FIGHT AT (%d,%d)\n",i,next.x,next.y);
        }
        t+=s;
    }
    return t;
}
int main(){
    while(cin>>n>>m){
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++){
                cin>>graph[i][j];
                dis[i][j]=INF;
            }
            int count=bfs();
            if(count!=-1){
                printf("It takes %d seconds to reach the target position, let me show you the way.\n",count);
                getpath(end);
                cout<<"FINISH"<<endl;
            }
            else cout<<"God please help our poor hero.\nFINISH"<<endl;
    }
	return 0;
}


2. 深度搜索

深度優先搜索也稱爲回溯搜索
回溯:能進則進,進不了則換,換不成則退
優點

空間需求少,深度優先搜索的存儲器要求是深度約束的線性函數

問題

可能搜索到錯誤的路徑上,在無限空間中可能陷入無限的搜索

最初搜索到的結果不一定是最優的

poj 2488  A Knight's Journey

#include <iostream>
using namespace std;
int dir[8][2]={-1,-2,1,-2,-2,-1,2,-1,-2,1,2,1,-1,2,1,2};
bool visit[9][9];
int pathx[100];
int pathy[100];
int p,q;
bool ok;
void dfs(int x,int y,int n){
    if(n==p*q){
		ok=1;	
		return ;
	}
	if(ok)
		return ;
	for(int i=0;i<8 && !ok;i++){
     	int xx=x+dir[i][0];
		int yy=y+dir[i][1];
		if(xx<1||xx>p||yy<1||yy>q||visit[xx][yy])
			continue;
		visit[xx][yy]=1;
		pathx[n]=xx;
		pathy[n]=yy;
		dfs(xx,yy,n+1);
		visit[xx][yy]=0;
	}
}
void printpath(){
	pathx[0]=1;
	pathy[0]=1;
    for(int i=0;i<=p*q-1;i++)
		printf("%c%d",pathy[i]+'A'-1,pathx[i]);
	cout<<endl<<endl;
}
int main(){
	int t;
	cin>>t;
	for(int c=1;c<=t;c++){
       cin>>p>>q;
       printf("Scenario #%d:\n",c);
	   ok=0;
	   memset(visit,0,sizeof visit);
	   memset(pathx,0,sizeof pathx);
	   memset(pathy,0,sizeof pathy);
	   visit[1][1]=1;
	   dfs(1,1,1);
     if(!ok){
          cout<<"impossible"<<endl<<endl;
		  continue;
	   }
	   printpath();
	}
}

鋪放矩形塊 (IOI 95)

This program is straightforward, but a bit long due to the geometry involved.

There are 24 permutations of the 4 rectangles, and for each permutation, 16 different ways to orient them. We generate all such orientations of permutations, and put the blocks together in each of the 6 different ways, recording the smallest rectangles we find.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Rect Rect;
struct Rect {
    int wid;
    int ht;
};

Rect rotate(Rect r)
{
    Rect nr;

    nr.wid = r.ht;
    nr.ht = r.wid;
    return nr;
}
int max(int a, int b){return a > b ? a : b;}
int min(int a, int b){return a < b ? a : b;}

int tot;
int bestarea;
int bestht[101];

void record(Rect r)
{
    int i;

    if(r.wid*r.ht < tot)
        *(long*)0=0;

    if(r.wid*r.ht < bestarea || bestarea == 0) {
        bestarea = r.wid*r.ht;
        for(i=0; i<=100; i++)
            bestht[i] = 0;
    }
    if(r.wid*r.ht == bestarea)
        bestht[min(r.wid, r.ht)] = 1;
}

void check(Rect *r)
{
    Rect big;
    int i;

    /* schema 1: all lined up next to each other */
    big.wid = 0;
    big.ht = 0;
    for(i=0; i<4; i++) {
        big.wid += r[i].wid;
        big.ht = max(big.ht, r[i].ht);
    }
    record(big);

    /* schema 2: first three lined up, fourth on bottom */
    big.wid = 0;
    big.ht = 0;
    for(i=0; i<3; i++) {
        big.wid += r[i].wid;
        big.ht = max(big.ht, r[i].ht);
    }
    big.ht += r[3].ht;
    big.wid = max(big.wid, r[3].wid);
    record(big);

    /* schema 3: first two lined up, third under them, fourth to side */
    big.wid = r[0].wid + r[1].wid;
    big.ht = max(r[0].ht, r[1].ht);
    big.ht += r[2].ht;
    big.wid = max(big.wid, r[2].wid);
    big.wid += r[3].wid;
    big.ht = max(big.ht, r[3].ht);
    record(big);

    /* schema 4, 5: first two rectangles lined up, next two stacked */
    big.wid = r[0].wid + r[1].wid;
    big.ht = max(r[0].ht, r[1].ht);
    big.wid += max(r[2].wid, r[3].wid);
    big.ht = max(big.ht, r[2].ht+r[3].ht);
    record(big);

    /*
     * schema 6: first two pressed next to each other, next two on top, like: 
     * 2 3
     * 0 1
     */
    big.ht = max(r[0].ht+r[2].ht, r[1].ht+r[3].ht);
    big.wid = r[0].wid + r[1].wid;

    /* do 2 and 1 touch? */
    if(r[0].ht < r[1].ht)
        big.wid = max(big.wid, r[2].wid+r[1].wid);
    /* do 2 and 3 touch? */
    if(r[0].ht+r[2].ht > r[1].ht)
        big.wid = max(big.wid, r[2].wid+r[3].wid);
    /* do 0 and 3 touch? */
    if(r[1].ht < r[0].ht)
        big.wid = max(big.wid, r[0].wid+r[3].wid);

    /* maybe 2 or 3 sits by itself */
    big.wid = max(big.wid, r[2].wid);
    big.wid = max(big.wid, r[3].wid);
    record(big);    
}

void checkrotate(Rect *r, int n)
{
    if(n == 4) {
        check(r);
        return;
    }

    checkrotate(r, n+1);
    r[n] = rotate(r[n]);
    checkrotate(r, n+1);
    r[n] = rotate(r[n]);
}

void checkpermute(Rect *r, int n)
{
    Rect t;
    int i;

    if(n == 4)
        checkrotate(r, 0);

    for(i=n; i<4; i++) {
        t = r[n], r[n] = r[i], r[i] = t;    /* swap r[i], r[n] */
        checkpermute(r, n+1);
        t = r[n], r[n] = r[i], r[i] = t;    /* swap r[i], r[n] */
    }
}

int main(void)
{
    Rect r[4];
    int i;

    for(i=0; i<4; i++)
        scanf( "%d %d", &r[i].wid, &r[i].ht);

    tot=(r[0].wid*r[0].ht+r[1].wid*r[1].ht+r[2].wid*r[2].ht+r[3].wid*r[3].ht);

    checkpermute(r, 0);
    printf( "%d\n", bestarea);
    for(i=0; i<=100; i++)
        if(bestht[i])
            printf( "%d %d\n", i, bestarea/i);
    return 0;
}

clocks


#include <stdio.h>

int a[9][9]= { {3,3,3,3,3,2,3,2,0},
               {2,3,2,3,2,3,1,0,1},
               {3,3,3,2,3,3,0,2,3},
               {2,3,1,3,2,0,2,3,1},
               {2,3,2,3,1,3,2,3,2},
               {1,3,2,0,2,3,1,3,2},
               {3,2,0,3,3,2,3,3,3},
               {1,0,1,3,2,3,2,3,2},
               {0,2,3,2,3,3,3,3,3} };
int v[9];

int main() {
    int i,j,k;

    for (i=0; i<9; i++) {
        scanf("%d",&k);
        for(j=0; j<9; j++)
             v[j]=(v[j]+(4-k/3)*a[i][j])%4;
    }

    k=0;
    for (i=0; i<9; i++)
        for (j=0; j<v[i]; j++)
            if (!k) { printf("%d",i+1); k=1; }
            else    printf(" %d",i+1);
    printf("\n");
    return 0;
}



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