第三周算法解题报告

A strange lift
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 205 Accepted Submission(s) : 51
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 <= Ki <= N) on every floor.The lift have just two buttons: up and down.When you at floor i,if you press the button “UP” , you will go up Ki floor,i.e,you will go to the i+Ki th floor,as the same, if you press the button “DOWN” , you will go down Ki floor,i.e,you will go to the i-Ki th floor. Of course, the lift can’t go up high than N,and can’t go down lower than 1. For example, there is a buliding with 5 floors, and k1 = 3, k2 = 3,k3 = 1,k4 = 2, k5 = 5.Begining from the 1 st floor,you can press the button “UP”, and you’ll go up to the 4 th floor,and if you press the button “DOWN”, the lift can’t do it, because it can’t go down to the -2 th floor,as you know ,the -2 th floor isn’t exist.
Here comes the problem: when you are on floor A,and you want to go to floor B,how many times at least he has to press the button “UP” or “DOWN”?
Input
The input consists of several test cases.,Each test case contains two lines.
The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2,…kn.
A single 0 indicate the end of the input.
Output
For each case of the input output a interger, the least times you have to press the button when you on floor A,and you want to go to floor B.If you can’t reach floor B,printf “-1”.
Sample Input
5 1 5
3 3 1 2 5
0
Sample Output
3
解题思路:这是一道简单的广度搜索题,题目大意为:在一个N层高的楼有一个奇怪的电梯,在每一层只能上升或下降一个特定的层数,中间不会停止,在给定的条件下,问能不能到达指定楼层,可以到达的话返回转操作次数,不可以的话返回-1。

#include<iostream>
#include<deque>
#include<cstring> 
using namespace std;
int main()
{
 int i,s,t,N,x,y,f[201],a[201];
 bool b[201];   //用来标记走过的楼层,避免出现死循环
 deque<int> Q;  //定义队列Q
 while(cin>>N)
 {
  Q.clear();
  if(!N) break;
  memset(b,0,sizeof(b));
  memset(a,0,sizeof(a));
  cin>>s>>t;
  for(i=1;i<=N;i++)
  {
   cin>>f[i];     //记录每层的运动规律
  }
  Q.push_back(s);
  x=Q.front();
  b[x]=1;
  while(x!=t)
  {
   y=f[x];
   if(x+y<=N&&!b[x+y])    
   {
    b[x+y]=1;
    Q.push_back(x+y);
    a[x+y]=a[x]+1;
   }
   if(x-y>=1&&!b[x-y])
   {
    b[x-y]=1;
    Q.push_back(x-y);
    a[x-y]=a[x]+1;
   }
   Q.pop_front();
   if(Q.empty()) break;
   x=Q.front();
  }
  if(x==t) cout<<a[x]<<endl;
  else cout<<"-1"<<endl;
 }
 return 0;
}

A计划
Time Limit : 3000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 56 Accepted Submission(s) : 18
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验。魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长生不老。年迈的国王正是心急如焚,告招天下勇士来拯救公主。不过公主早已习以为常,她深信智勇的骑士LJ肯定能将她救出。
现据密探所报,公主被关在一个两层的迷宫里,迷宫的入口是S(0,0,0),公主的位置用P表示,时空传输机用#表示,墙用表示,平地用.表示。骑士们一进入时空传输机就会被转到另一层的相对位置,但如果被转到的位置是墙的话,那骑士们就会被撞死。骑士们在一层中只能前后左右移动,每移动一格花1时刻。层间的移动只能通过时空传输机,且不需要任何时间。
Input
输入的第一行C表示共有C个测试数据,每个测试数据的前一行有三个整数N,M,T。 N,M迷宫的大小N
M(1 <= N,M <=10)。T如上所意。接下去的前NM表示迷宫的第一层的布置情况,后NM表示迷宫第二层的布置情况。
Output
如果骑士们能够在T时刻能找到公主就输出“YES”,否则输出“NO”。
Sample Input
1
5 5 14
S*#*.
.#…

**.
…#.
.P
#.

**
.
*.#…
Sample Output
YES
Source
HDU 2007-6 Programming Contest
解题思路:广度搜索题,本题需要注意的是,遇到传送机传送到另一层时,若另一层的相应位置也是传送机,则会陷入死循环,同样无法找到公主。

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include<iostream>
using namespace std;
int N,M,T;
char map[2][11][11];
int book[2][11][11];
int head[3],tail[3];
int go[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; 
struct node 
{
    int x;
    int y;
    int floor;
    int step;
}; 
int check (int floor,int x,int y){
    if (x<0 || y<0 || x>=N || y>=M){    //检查是否在图内 
        return 1;
    }
    if (map[floor][x][y] == '*'){      //检查点是否是墙 
        return 1;
    }
    return 0;
}
void bfs (){
    memset(book,0,sizeof(book));
    node a,next;
    queue<node> Q;
    a.floor = head[0];
    a.x = head[1];
    a.y = head[2];
    a.step = 0;
    book[head[0]][head[1]][head[2]] = 1;
    Q.push(a);
    while (!Q.empty()){
        a = Q.front();
        Q.pop();
        if (a.floor == tail[0] && a.x == tail[1] && a.y == tail[2]){
            printf("YES\n");
            return ;
        }
        if (a.step >= T){
            break;
        }
        for (int i = 0; i<4; i++){
            next = a;
            next.x += go[i][0];
            next.y += go[i][1];
            next.step++;
            if (check(next.floor,next.x,next.y)){         //检查扩展后的点是否在边界内而且不是墙 
                continue;
            }
            if (book[next.floor][next.x][next.y]){        //检查有没有重复扩展相同的点  
                continue;
            }
            book[next.floor][next.x][next.y] = 1;        //将扩展后的点标记为1,表示已走过
            if (map[next.floor][next.x][next.y] == '#'){
                next.floor = !next.floor;
                if (check(next.floor,next.x,next.y))
                    continue;
                if (book[next.floor][next.x][next.y])
                    continue;
                if (map[next.floor][next.x][next.y] == '*' || map[next.floor][next.x][next.y] == '#')
                    continue;
                book[next.floor][next.x][next.y] = 1;     
            }
            if (next.floor == tail[0] && next.x == tail[1] && next.y == tail[2]){
                printf("YES\n");
                return ;
            } 
            Q.push(next);
        }
    }
    printf("NO\n");
} 
int main()
{
   int C;
   scanf("%d",&C);
   while (C--){
           scanf("%d%d%d",&N,&M,&T);
           for (int k = 0; k<2; k++){
               for (int i = 0; i<N; i++){
                   scanf("%s",map[k][i]);
                   for (int j = 0; j<M; j++){
                       if (map[k][i][j] == 'S'){
                           head[0] = k;
                           head[1] = i;
                           head[2] = j;
                       }
                       else if (map[k][i][j] == 'P'){
                           tail[0] = k;
                           tail[1] = i;
                           tail[2] = j;
                       }
                   }
               }
           }
           bfs();
   }
    return 0;
}

N皇后问题
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 48 Accepted Submission(s) : 21
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input
1
8
5
0
Sample Output
1
92
10
Author
cgf
Source
2008 HZNU Programming Contest
解题思路:简单的深度搜索题。具体解析看代码。

#include <cstdio>
#include <cmath>
int qizi[20];//qizi【i】=j表示 第i行第j列下有棋 
int biao[11];//结果存到表中,不存会超时 
int n;
int qingkuang;
bool judge(int hang)
{
    for(int i=1;i<hang;i++)//扫之前下过棋每一行是否有与此次所下棋的位置同列的 或同对角线的 
    {
        if(qizi[i]==qizi[hang]||abs(hang-i)==abs(qizi[hang]-qizi[i]))//对角线的话斜率的绝对值=1 
        return false; 
    }
    return true;
}
 
void dfs(int hang)
{
    if(hang==n+1)//比如n=2,然后该第二行下棋了,第二行如果能成功选择的话,那么那么新的行数3就等于n+1=3了 ,实在不懂举个例子看看 
    qingkuang++;
    else
    {
        for(int j=1;j<=n;j++)//在该行选第几列 
        {
            qizi[hang]=j;
            if(judge(hang))
            {
                dfs(hang+1);//在本行能下棋的话,就接着下下一行的棋 
            }
        } 
    }
}
void cnt(int n)
{
    dfs(1);//从第一行开始选地方下棋 
}
int main()
{
    for(n=1;n<=10;n++)
    {
        qingkuang=0;
        cnt(n);
        biao[n]=qingkuang;
    }
    int q;
    while(scanf("%d",&q)!=EOF)
    {
        if(q==0)
        break;
        printf("%d\n",biao[q]);
    }
    return 0;
}

Sudoku Killer
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 27 Accepted Submission(s) : 12
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视。
据说,在2008北京奥运会上,会将数独列为一个单独的项目进行比赛,冠军将有可能获得的一份巨大的奖品———HDU免费七日游外加lcy亲笔签名以及同hdu acm team合影留念的机会。
所以全球人民前仆后继,为了奖品日夜训练茶饭不思。当然也包括初学者linle,不过他太笨了又没有多少耐性,只能做做最最基本的数独题,不过他还是想得到那些奖品,你能帮帮他吗?你只要把答案告诉他就可以,不用教他是怎么做的。
数独游戏的规则是这样的:在一个9x9的方格中,你需要把数字1-9填写到空格当中,并且使方格的每一行和每一列中都包含1-9这九个数字。同时还要保证,空格中用粗线划分成9个3x3的方格也同时包含1-9这九个数字。比如有这样一个题,大家可以仔细观察一下,在这里面每行、每列,以及每个3x3的方格都包含1-9这九个数字。
例题:
在这里插入图片描述
答案:
在这里插入图片描述
Input
本题包含多组测试,每组之间由一个空行隔开。每组测试会给你一个 99 的矩阵,同一行相邻的两个元素用一个空格分开。其中1-9代表该位置的已经填好的数,问号(?)表示需要你填的数。
Output
对于每组测试,请输出它的解,同一行相邻的两个数用一个空格分开。两组解之间要一个空行。
对于每组测试数据保证它有且只有一个解。
Sample Input
7 1 2 ? 6 ? 3 5 8
? 6 5 2 ? 7 1 ? 4
? ? 8 5 1 3 6 7 2
9 2 4 ? 5 6 ? 3 7
5 ? 6 ? ? ? 2 4 1
1 ? 3 7 2 ? 9 ? 5
? ? 1 9 7 5 4 8 6
6 ? 7 8 3 ? 5 1 9
8 5 9 ? 4 ? ? 2 3
Sample Output
7 1 2 4 6 9 3 5 8
3 6 5 2 8 7 1 9 4
4 9 8 5 1 3 6 7 2
9 2 4 1 5 6 8 3 7
5 7 6 3 9 8 2 4 1
1 8 3 7 2 4 9 6 5
2 3 1 9 7 5 4 8 6
6 4 7 8 3 2 5 1 9
8 5 9 6 4 1 7 2 3
Author
linle
Source
ACM暑期集训队练习赛(三)
解题思路:本题采用结构体数组将将每个空格的位置先储存起来。然后再把数字一个个代进去尝试,对于判断3
3矩阵内是否有重复数字,可以先算出矩阵所在的行列,例如,a[2][2]位于[1][1]矩阵,然后再进行判重。

#include<bits/stdc++.h>
using namespace std;
int a[16][16];
struct point{
    int x,y;
}memor[106];
int sum;
bool isok(int k,int p)
{
    for(int i=1;i<=9;++i)
    {
        if(a[memor[p].x][i]==k||a[i][memor[p].y]==k)return 0;
    }
    int xx=((memor[p].x-1)/3)*3+1,yy=((memor[p].y-1)/3)*3+1;//这里矩阵是从(1,1)开始的,所以要-1。。。+1;
    for(int i=xx;i<=xx+2;++i)
        for(int j=yy;j<=yy+2;++j)
        {
            if(a[i][j]==k)return 0;
 
        }
    return 1;
}
void search(int p)
{
    if(p>sum)
    {
        for(int i=1;i<=9;++i)
        {
            cout<<a[i][1];
            for(int j=2;j<=9;++j)cout<<" "<<a[i][j];//杭电的格式控制的还是很严格的;
            cout<<endl;
        }
        return ;
    }
 
    for(int i=1;i<=9;++i)
    {
        if(isok(i,p)==1)  //判重函数;
        {
            a[memor[p].x][memor[p].y]=i;
            search(p+1);
            a[memor[p].x][memor[p].y]=0;
        }
    }
}
int main()
{
    //freopen("1.txt","r",stdin);
    char ch;
    int flag=0;
    while(cin>>ch)     //单独输入(1,1)点以满足多组测试数据的要求;
    {
        sum=0;
        memset(a,0,sizeof(a));
        memset(memor,0,sizeof(memor));
        if(ch=='?')
        {
            a[1][1]=0;
            sum++;
            memor[sum].x=1;
            memor[sum].y=1;
        }
        else a[1][1]=ch-'0';
        char zh;
        for(int i=1;i<=9;++i)
            for(int j=1;j<=9;++j)
            {
                if(i==1&&j==1)continue;
                cin>>zh;
                if(zh=='?')
                {
                    a[i][j]=0;
                    sum++;
                    memor[sum].x=i;
                    memor[sum].y=j;
                }
                else   a[i][j]=zh-'0';
                }
 
        if(flag++)cout<<endl; //flag用的也是挺巧妙的;
        search(1);
    }
    return 0;
}

Oil Deposits
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 80 Accepted Submission(s) : 33
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.
Input
The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either *', representing the absence of oil, or@’, representing an oil pocket.
Output
For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.
Sample Input
1 1
*
3 5
@@

@
@@

1 8
@@***@
5 5
****@
@@@
@**@
@@@
@
@@**@
0 0
Sample Output
0
1
2
2
Source
Mid-Central USA 1997
解题思路:本题为标准的深度搜索题。

#include <cstdio>
#include <cstring>
using namespace std;
char a[105][105];
int n,m,i,j;
void dfs(int x,int y)
{
    a[x][y]='*';
    for(int dx=-1;dx<=1;dx++)    //以一个点为中心,判断他周围有无‘@’,一直搜索下去,直到没有相连通的‘@’
    for(int dy=-1;dy<=1;dy++){
        int nx=dx+x;
        int ny=dy+y;
        if(nx>=0&&nx<n&&ny>=0&&ny<m&&a[nx][ny]=='@') dfs(nx,ny);
    }
    return ;
}
void solve()
{
    int ans=0;
    for(i=0;i<n;i++)
    for(j=0;j<m;j++){
        if(a[i][j]=='@')
        {
            dfs(i,j);
            ans++;            //每遇到一个‘@’,就将连通快总数加1,并通过dfs把相连通的‘@’都转化成‘*’
        }
    }
    printf("%d\n",ans);
}
int main()
{
    while(1){
        scanf("%d%d",&n,&m);
        if(n==0&&m==0) break;
        memset(a,0,sizeof(a));
        for(i=0;i<n;i++){
            scanf("%s",a[i]);     //输入的时候要注意,如果输入%c,记得加getchar();
        }
        solve();
    }
    return 0;
}

本周算法小结:
DFS 算法
思想:一直往深处走,直到找到解或者走不下去为止
在这里插入图片描述
BFS算法
在这里插入图片描述
DFS:使用栈保存未被检测的结点,结点按照深度优先的次序被访问并依次被压入栈中,并以相反的次序出栈进行新的检测。
在这里插入图片描述
BFS:使用队列保存未被检测的结点。结点按照宽度优先的次序被访问和进出队列。
在这里插入图片描述
框架:
BFS:
**

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=100;
bool vst[maxn][maxn]; // 访问标记
int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量
struct State // BFS 队列中的状态数据结构
{
int x,y; // 坐标位置
int Step_Counter; // 搜索步数统计器
};
State a[maxn];
bool CheckState(State s) // 约束条件检验
{
if(!vst[s.x][s.y] && ...) // 满足条件
return 1;
else // 约束条件冲突
return 0;
}
void bfs(State st)
{
queue <State> q; // BFS 队列
State now,next; // 定义2 个状态,当前和下一个
st.Step_Counter=0; // 计数器清零
q.push(st); // 入队
vst[st.x][st.y]=1; // 访问标记
while(!q.empty())
{
now=q.front(); // 取队首元素进行扩展
if(now==G) // 出现目标态,此时为Step_Counter 的最小值,可以退出即可
{
...... // 做相关处理
return;
}
for(int i=0;i<4;i++)
{
next.x=now.x+dir[i][0]; // 按照规则生成下一个状态
next.y=now.y+dir[i][1];
next.Step_Counter=now.Step_Counter+1; // 计数器加1
if(CheckState(next)) // 如果状态满足约束条件则入队
{
q.push(next);
vst[next.x][next.y]=1; //访问标记
}
}
q.pop(); // 队首元素出队
}
 return;
}
int main()
{
......
 return 0;
}

DFS:
DFS:
/*
该DFS 框架以2D 坐标范围为例,来体现DFS 算法的实现思想。
*/

#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=100;
bool vst[maxn][maxn]; // 访问标记
int map[maxn][maxn]; // 坐标范围
int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量,(x,y)周围的四个方向

bool CheckEdge(int x,int y) // 边界条件和约束条件的判断
{
if(!vst[x][y] && ...) // 满足条件
return 1;
else // 与约束条件冲突
return 0;
}

void dfs(int x,int y)
{
vst[x][y]=1; // 标记该节点被访问过
if(map[x][y]==G) // 出现目标态G
{
...... // 做相应处理
return;
}
for(int i=0;i<4;i++)
{
if(CheckEdge(x+dir[i][0],y+dir[i][1])) // 按照规则生成下一个节点
dfs(x+dir[i][0],y+dir[i][1]);
}
return; // 没有下层搜索节点,回溯
}
int main()
{
......
return 0;
}

摘自:https://blog.csdn.net/u011437229/article/details/53188837

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值