ACM Steps_Chapter Four_Section2

Collect More Jewels

/*
HDU 1044 Collect More Jewels
走迷宫,问在规定时间内从起点到终点最多可以收集到宝物的价值是多少。

先bfs找出所有宝物及起点和终点这些位置之间的最短距离,再起点dfs最大。
加个剪枝,如果已经拿到所有宝物了,就不再搜索。


AC G+ 31MS 560K
*/
/*
在一个迷宫中,从起点走到终点,还有几个宝物,问在给定的时间内,
到达终点后所能获取的最大价值。

思路:

先用bfs求出入口,宝物,出口,两两之间的最短距离。

在用dfs搜索所有情况,求出从入口走到出口能获得的最大价值。

熟悉两种搜索的优缺点:

BFS: 对于解决最短或最少问题特别有效,而且寻找深度小,
但缺点是内存耗费量大(需要开大量的数组单元用来存储状态)。
DFS:对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度迅速,
然而在深度很大的情况下效率不高
*/
#include<stdio.h>
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
int W,H,L,M;//区域是H行W列的,L是时间限制,M是宝石的数量
int val[60];//宝石的价值,1-M
char map[60][60];
bool used[60][60];//BFS时访问标记
bool vis[60];//dfs时访问标记
int step[60][60];
int ans;//结果
int sum;//所有的宝石的价值总和
int move[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
int dis[60][60];//记录初始位置、各宝石和出口两两间的距离
queue<int>q;

//从(x1,y1)点到其它点的距离,s(0-M+1)是该点编号,0表示初始位置
//M+1表示出口,1-M表示第i个宝物堆
void bfs(int x1,int y1,int s)
{
    while(!q.empty())q.pop();
    memset(used,false,sizeof(used));
    memset(step,0,sizeof(step));
    int u=x1*W+y1;
    q.push(u);
    used[x1][y1]=true;
    step[x1][y1]=0;
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        int x=u/W;
        int y=u%W;
        for(int i=0;i<4;i++)
        {
            int xx=x+move[i][0];
            int yy=y+move[i][1];
            if(xx<0||xx>=H||yy<0||yy>=W)continue;
            if(used[xx][yy]||map[xx][yy]=='*')continue;

            used[xx][yy]=true;
            step[xx][yy]=step[x][y]+1;
            if(map[xx][yy]=='@')dis[s][0]=step[xx][yy];
            else if(map[xx][yy]=='<') dis[s][M+1]=step[xx][yy];
            else if(map[xx][yy]>='A'&&map[xx][yy]<='J')
                dis[s][map[xx][yy]-'A'+1]=step[xx][yy];
            q.push(xx*W+yy);
        }
    }
}

//dfs,s表示当前点,value表示获得的价值,time表示花费的时间
void dfs(int s,int value,int time)
{
    if(time>L)return;//超出限制时间
    if(ans==sum) return;//已经得到了最大的价值,剪枝(没有这个会超时)
    if(s>M)
    {
        if(value>ans)ans=value;
        return;
    }
    for(int i=0;i<=M+1;i++)
    {
        if(dis[s][i]==0||vis[i])continue;
        vis[i]=true;
        dfs(i,value+val[i],time+dis[s][i]);
        vis[i]=false;
    }
}
int main()
{
   // freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    scanf("%d",&T);
    int iCase=0;
    while(T--)
    {
        memset(dis,0,sizeof(dis));
        iCase++;
        scanf("%d%d%d%d",&W,&H,&L,&M);
        sum=0;
        ans=-1;
        for(int i=1;i<=M;i++)
        {
            scanf("%d",&val[i]);
            sum+=val[i];
        }
        val[0]=val[M+1]=0;//这个很重要啊,WR到死啊
        for(int i=0;i<H;i++)
          scanf("%s",&map[i]);
        for(int i=0;i<H;i++)
          for(int j=0;j<W;j++)
          {
              if(map[i][j]=='@') bfs(i,j,0);
              else if(map[i][j]=='<') bfs(i,j,M+1);
              else if(map[i][j]>='A'&&map[i][j]<='J')
                 bfs(i,j,map[i][j]-'A'+1);

          }
        memset(vis,false,sizeof(vis));
        vis[0]=true;
        dfs(0,0,0);

        printf("Case %d:\n",iCase);
        if(ans>=0)printf("The best score is %d.\n",ans);
        else printf("Impossible\n");

        if(T>0)printf("\n");

    }
    return 0;
}

Rescue

#include<stdio.h>
#define max 32000
int n, m, time, visited[202][202], map[202][202], mx[5] = {0, 0, 0, -1, 1}, my[5] = {0, 1, -1, 0, 0}, ax, ay, ex, ey;
void init();
int dfs(int x, int y, int t);
int main()
{
    init();
    return 0;
}
void init()
{
    int i, j;
    char str[203];
    while(scanf("%d %d\n", &n, &m) != EOF){
        time = max;
        for(i = 0; i <= n + 2; ++i)
            for(j = 0; j <= m + 2; ++j){
                map[i][j] = -1;
                visited[i][j] = -1;
            }
        for(i = 1; i <= n; ++i){
            gets(str);
            for(j = 0; j <= m - 1; ++j)
                if(str[j] == '.')
                    visited[i][j + 1] = 1;
                else
                    if(str[j] == 'a'){
                        ax = i;
                        ay = j + 1;
                    }
                    else
                        if(str[j] == 'r'){
                            ex = i;
                            ey = j + 1;
                            visited[i][j + 1] = 1;
                        }
                        else
                            if(str[j] == 'x')
                                visited[i][j + 1] = 2;
        }
        dfs(ax, ay, 0);
        if(time != max)
            printf("%d\n", time);
        else
            printf("Poor ANGEL has to stay in the prison all his life.\n" );
    }
}
int dfs(int x, int y, int t){
    int i, ch, xn, yn;
    if(x == ex && y == ey){
        if(t < time)
            time = t;
        return 0;
    }
    else{
        for(i = 1; i <= 4; ++i){
            xn = x + mx[i];
            yn = y + my[i];
            if((visited[xn][yn] == 1 || visited[xn][yn] == 2) && t + visited[xn][yn] <= time){
                if(map[xn][yn] == -1 || t + visited[xn][yn] <= map[xn][yn]){
                    map[xn][yn] = t + visited[xn][yn];
                    ch = visited[xn][yn];
                    visited[xn][yn] = -1;
                    dfs(xn, yn, t + ch);
                    visited[xn][yn] = ch;
                }
            }
        }
    }
}

A strange lift

#include <iostream>
#include <algorithm>
#include <stdlib.h>
using namespace std;
const int M = 1005;
int n;
bool visit[M];
int buttom[M],step[M];
int loc[M];

int judge( int x )
{
    if( x >= 1 && x<=n )
        return 1;
    return 0;    
}

int BFS( int start , int end )
{
    int front , tail;
    front = tail = 0;
    loc[front++] = start;
    while( front > tail ){
           int x = loc[tail++];
           if( x == end )
               break;
           int up,down;
           up = x+buttom[x];
           down = x-buttom[x];
           if( !visit[up] && judge(up) ){
               visit[up] = true;
               step[up] = step[x]+1;
               loc[front++] = up;    
           }
           if( !visit[down] && judge(down) ){
               visit[down] = true;
               step[down] = step[x]+1;
               loc[front++] = down;    
           }
    }
    return step[end];
}

int main( )
{
    int start, end;
    while( scanf("%d",&n) == 1 && n ){
           scanf("%d%d",&start,&end);       
           for( int i=1 ; i<=n ; i++ ){
                scanf("%d",&buttom[i]);
                visit[i] = false;
                step[i] = 0;
           }
           if( start == end )
               printf("0\n");
           else{
               int ans;
               ans = BFS( start , end );
               if( ans == 0 )
                   printf("-1\n");
               else
                   printf("%d\n",step[end]);
           }
    }    
    return 0;
}

Knight Moves

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
struct node
{
 	int x, y;
 	int step;
};
queue<node>q;
node s, next;
char a[3], b[3];
int sx, sy, ex, ey, visit[9][9]; 
int dx[8] = {2, -2, 2, -2, 1, -1, 1, -1}; //direcito of '日'
int dy[8] = {1, 1, -1, -1, 2, 2, -2, -2}; 
int check(int x, int y) 
{
	if(x < 1 || x > 8 || y < 1 || y > 8)
  		return 0;
 	else
  		return 1;
}
void BFS()
{
	int i;
 	while(!q.empty()) //in cace of last time queue has elements
  		q.pop();
 	memset(visit, 0, sizeof(visit)); //initalization
 	s.x = sx;  s.y = sy;  s.step = 0; //start push in queue
 	q.push(s); 
 	visit[sx][sy] = 1; //mark it was visited
 	while(!q.empty())
 	{
  		s = q.front();
  		q.pop();    
   		if(s.x == ex && s.y == ey)
  		{
   			cout << "To get from " << a << " to "<< b 
   			<< " takes " << s.step << " knight moves." << endl;
   			break;
  		}
  		for(i = 0; i < 8; i++)
  		{
   			next.x = dx[i] + s.x;  
   			next.y = dy[i] + s.y;  
   			next.step = s.step + 1;          
   			if(!check(next.x, next.y))
    			continue;  
   			if(!visit[next.x][next.y])
   			{
    			q.push(next);
    			visit[next.x][next.y] = 1;       
   			}
  		}//end of direction for(...)
 	}//end of while(...)
}//end of BFS()
int main()
{
    while(cin >> a >> b)
 	{
  		sx = a[0] - 'a' + 1;
  		sy = a[1] - '0';
  		ex = b[0] - 'a' + 1;
  		ey = b[1] - '0';
  		BFS();
 	}
 	return 0;
}

Nightmare

#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;

int mp[10][10],m,n,Sx,Sy,Dx,Dy,flag,dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct point
{
	int x,y,time,step;
};

void bfs(int x,int y)
{
	int i;
	point t,tt;
	queue<point>Q;
	t.x=x;t.y=y;t.step=0;t.time=6;
	Q.push(t);
//	memset(visit,0,sizeof(visit));
	while(!Q.empty())
	{
		t=Q.front();
		Q.pop();//printf("%d,%d\n",t.x,t.y);
		for(i=0;i<4;i++)
		{
 			tt.x=t.x+dir[i][0];tt.y=t.y+dir[i][1];  tt.step=t.step+1;tt.time=t.time-1;
 		//	printf("\t%d,%d",tt.x,tt.y);
			if(tt.x<1||tt.x>m||tt.y<1||tt.y>n||mp[tt.x][tt.y]==0||tt.time==0)	continue;
			if(mp[tt.x][tt.y]==3){printf("%d\n",tt.step);return;}
			
		//	printf("!\n");
			
			if(mp[tt.x][tt.y]==4){
				mp[tt.x][tt.y]=0;
				tt.time=6;
			//	memset(visit,0,sizeof(visit));
			}
		//	mp[tt.x][tt.y]=0;
			Q.push(tt);
 		}
 	//	system("pause");
	}
	printf("-1\n");
	return;
}

int main()
{
	int T,i,j;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&m,&n);
		for(i=1;i<=m;i++)
		{
			for(j=1;j<=n;j++)
			{
				scanf("%d",&mp[i][j]);
				if(mp[i][j]==2) Sx=i,Sy=j;
			}
		}
		
		bfs(Sx,Sy);
		
	}
	return 0;
}

Hike on a Graph

#include <cstdio>
#include <string.h>
#include <queue>
using namespace std;
struct pos{int x,y,z;pos(int a,int b,int c){x=a,y=b,z=c;}};
int n,p1,p2,p3;
char map[60][60];
int vis[60][60][60];
/*
	BFS 三个点,x->i仅当color[x][i]=color[y][z] 
*/
int bfs(){
	memset(vis,0,sizeof vis); 
	queue<pos> q;
	q.push(pos(p1,p2,p3));
	vis[p1][p2][p3]=1;
	
	while(!q.empty()){
		pos p=q.front();q.pop();
		
		if(p.x==p.y&&p.y==p.z)return vis[p.x][p.y][p.z]-1;
		
		for(int i=1;i<=n;i++){
			if(map[p.x][p.y]==map[p.z][i]&&!vis[p.x][p.y][i]){
				vis[p.x][p.y][i]=vis[p.x][p.y][p.z]+1;
				q.push(pos(p.x,p.y,i));
			}
			if(map[p.z][p.x]==map[p.y][i]&&!vis[p.x][i][p.z]){
				vis[p.x][i][p.z]=vis[p.x][p.y][p.z]+1;
				q.push(pos(p.x,i,p.z));
			}
			if(map[p.y][p.z]==map[p.x][i]&&!vis[i][p.y][p.z]){
				vis[i][p.y][p.z]=vis[p.x][p.y][p.z]+1;
				q.push(pos(i,p.y,p.z));	
			}
		}	
	}
	
	return -1;
}
int main(){
	while(scanf("%d",&n),n){
		scanf("%d%d%d",&p1,&p2,&p3);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				scanf(" %c",&map[i][j]);
		
		int r=bfs();			
		if(r==-1)printf("impossible\n");
		else printf("%d\n",r);
		
	}
	
	return 0;	
}

非常可乐

/*
首先剪枝是 如果s是奇数必然不行。
一看到要求最少的步数就知道用bfs了

我们用vis标记状态
每个状态有三个整数组成 表示这三个杯子里的可乐数量

然后对每个状态的递推是 6种 也就是3!种。从一个到到另一个 再标记 入队
*/
#include<iostream>
#include<queue>
#include<cstring>
#define N 105
using namespace std;
bool flag;
int s,n,m;
struct point
{
	int x,y,z;
	int step;
};
bool visited[N][N][N];
point s_pos;
int ok(point t)         //结束状态
{   
	if((t.x==t.y&&t.z==0)||(t.x==t.z&&t.y==0)||(t.y==t.z&&t.x==0))
		return 1;
	return 0;
}
void bfs()
{
	memset(visited,0,sizeof(visited));
	visited[s][0][0]=1;
	s_pos.x=s;   s_pos.y=0;  s_pos.z=0; s_pos.step=0;
	queue<point>Q;
	Q.push(s_pos);
	
	while(!Q.empty())
	{
		point p;
		int t;
		
		point temp=Q.front();
		Q.pop();
		if(ok(temp))
		{
			flag=1;
			cout<<temp.step<<endl;
			return ;
		}
		if(temp.x>0)
		{
			if(temp.y<n)
			{
				t=n-temp.y;
				p.z=temp.z;
				p.step=temp.step+1;
				if(temp.x>t)
				{	p.x=temp.x-t;	p.y=n;	}
				else
				{   p.x=0;  	p.y=temp.y+temp.x; }
				if(!visited[p.x][p.y][p.z])
				{
					visited[p.x][p.y][p.z]=1;
					Q.push(p);                                     //x->y
				}
			}
			if(temp.z<m)
			{
				
				t=m-temp.z;
				p.y=temp.y;
				
				if(temp.x>t)
				{	p.x=temp.x-t;	p.z=m;p.step=temp.step+1;	}
				else
				{	p.x=0;	p.z=temp.z+temp.x;	p.step=temp.step+1;	}
				if(!visited[p.x][p.y][p.z])
				{
					visited[p.x][p.y][p.z]=1;
					Q.push(p);                                     
				}         //x->z
			}
			
		}
		if(temp.y>0)
		{
			if(temp.x<s)
			{
				t=s-temp.x;	
				p.z=temp.z;
				if(temp.y>t)
				{	p.y=temp.y-t;	p.x=s;		p.step=temp.step+1;		}
				else
				{   p.y=0;  	p.x=temp.y+temp.x;  p.step=temp.step+1;	}
				if(!visited[p.x][p.y][p.z])
				{
					visited[p.x][p.y][p.z]=1;
					Q.push(p);                                     
				}                               //y->x
			}
			if(temp.z<m)
			{
				
				t=m-temp.z;
				p.x=temp.x;
				
				if(temp.y>t)
				{	p.y=temp.y-t;	p.z=m;p.step=temp.step+1;	}
				else
				{	p.y=0;	p.z=temp.z+temp.y;	p.step=temp.step+1;	}
				if(!visited[p.x][p.y][p.z])
				{
					visited[p.x][p.y][p.z]=1;
					Q.push(p);                                     
				}                              //y->z
			}
			
		}
		if(temp.z>0)
		{
			if(temp.x<s)
			{
				t=s-temp.x;
				p.y=temp.y;
				if(temp.z>t)
				{	p.z=temp.z-t; p.x=s;p.step=temp.step+1;     }           
				else
				{   p.z=0;    p.x=temp.z+temp.x;p.step=temp.step+1;  }
				if(!visited[p.x][p.y][p.z])
				{
					visited[p.x][p.y][p.z]=1;
					Q.push(p);                                     
				}                               //z->x
			}
			if(temp.y<n)
			{
				
				t=n-temp.y;
				p.x=temp.x;
				if(temp.z>t)
				{   p.z=temp.z-t;  p.y=n;p.step=temp.step+1;     }
				else
				{   p.z=0;   p.y=temp.z+temp.y;   p.step=temp.step+1;}   
				if(!visited[p.x][p.y][p.z])
				{
					visited[p.x][p.y][p.z]=1;
					Q.push(p);                                     
				}                            //z->y
			}
		}
		
	}
	
	
}
int main()
{
	while(cin>>s>>n>>m,s+n+m)
	{
		flag=0;
		bfs();
		if(!flag)
			cout<<"NO"<<endl;
	}
	return 0;
}

Treasure of the Chimp Island

/*
题意:给最大100*100的地图,$代表财宝,*表示不可达,. 表示走过不需要花费,
1~9表示走过需要花费1~9,边界格子为* ,#(表示从此进入可以带0个
         炸药)或A~Z(表示从此进入可以带1~26个炸药),现在一个人可以从边界非*处进入,
		 最小到达$位置的最小花费是多少。
题解:如果考虑枚举起点的话,最坏情况边界全部为起点,
这样至少100*100*100*100的复杂度就悲剧了。 所以想从$开始bfs 最短路,
dis[ i ][ j ][ k ]表示
         到达[ i , j ]点已经用k个炸弹的最小花费,注意边界点不入队列即可。
         */
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <queue>
#define MIN(a , b) ((a) < (b) ? (a) : (b))
using namespace std;
const int inf = 1 << 29;
const int maxn = 102;
const int maxm = 27;
const int move[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
struct ddd
{
    int x,y,use;
    int val;
    ddd(){}
    ddd(int xx,int yy,int uu,int vv)
    {
        x = xx;
        y = yy;
        use = uu;
        val = vv;
        return;
    }
    bool operator < (const ddd &other) const
    {
        return val > other.val;
    }
};
priority_queue <ddd> Q;
int dis[maxn][maxn][maxm];
bool vis[maxn][maxn][maxm];
char map[maxn][maxn];
int m,n;

void init()
{
    memset(vis,false,sizeof(vis));
    while(!Q.empty()) Q.pop();
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            for(int k=0;k<maxm;k++)
            {
                dis[i][j][k] = inf;
            }
            if(map[i][j] == '$')
            {
                dis[i][j][0] = 0;
                Q.push(ddd(i,j,0,0));
                map[i][j] = '.';
            }
        }
    }
    return;
}

bool judge(int x,int y)
{
    if(x >= 0 && y >= 0 && x < n && y < m && map[x][y] != '*')
    {
        return true;
    }
    return false;
}

int bound(int x,int y)
{
    if(x == 0 || y == 0 || x == n-1 || y == m-1)
    {
        if(map[x][y] == '#') return 0;
        else if(map[x][y] >= 'A' && map[x][y] <= 'Z') return map[x][y] - 'A' + 1;
        return -1;
    }
    return -1;
}

void bfs()
{
    int res = inf;
    ddd cur;
    while(!Q.empty())
    {
        cur = Q.top();
        Q.pop();
        if(vis[cur.x][cur.y][cur.use]) continue;
        vis[cur.x][cur.y][cur.use] = true;
        for(int i=0;i<4;i++)
        {
            int tx = cur.x + move[i][0];
            int ty = cur.y + move[i][1];
            if(judge(tx , ty))
            {
                int d = bound(tx , ty);
                if(d >= 0)
                {
                    if(d >= cur.use) res = MIN(res , cur.val);
                    continue;
                }
                if(map[tx][ty] == '.')
                {
                    if(vis[tx][ty][cur.use] == false && dis[tx][ty][cur.use] > cur.val)
                    {
                        dis[tx][ty][cur.use] = cur.val;
                        Q.push(ddd(tx , ty , cur.use , cur.val));
                    }
                }
                else
                {
                    int cost = map[tx][ty] - '0';
                    if(vis[tx][ty][cur.use] == false && dis[tx][ty][cur.use] > cur.val + cost)
                    {
                        dis[tx][ty][cur.use] = cur.val + cost;
                        Q.push(ddd(tx , ty , cur.use , cur.val + cost));
                    }
                    if(cur.use < 26 && vis[tx][ty][cur.use + 1] == false && dis[tx][ty][cur.use + 1] > cur.val)
                    {
                        dis[tx][ty][cur.use + 1] = cur.val;
                        Q.push(ddd(tx , ty , cur.use + 1 , cur.val));
                    }
                }
            }
        }
    }
    if(res == inf) puts("IMPOSSIBLE");
    else printf("%d\n",res);
    return;
}

int main()
{
    while(true)
    {
        n = 0;
        while(gets(map[n]))
        {
            if(map[n][0] == '-') return 0;
            if(map[n][0] == '\0') break;
            n++;
        }
        m = strlen(map[0]);
        init();
        bfs();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值