深度优先搜索刷题记

如果您不会单源最短路径,出门右拐搜索。

本刷题记会随时更新。啊你们不要说我找的都是水题啊!

Codeforces Beta Round #3 C.Tic-tac-toe

翻译

一个 \(3*3\) 棋盘,要你判断 \(A,B\) 哪个选手赢了,或者该谁下了,或者平局,或者棋盘不符合规则。

思路

水题,暴力可做,但是我们可以搜索出所有的情况,保存在一个 map里,然后对于输出直接查找即可。

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i=0;i<int(n);i++)
using namespace std;
string grid=".........";
map<string,string>ans;
int wins(char p)
{
    rep(i,3) if(grid[i*3]==p&&grid[i*3+1]==p&&grid[i*3+2]==p)
        return true;
    rep(i,3) if(grid[i]==p&&grid[i+3]==p&&grid[i+6]==p)
        return true;
    if(grid[0]==p&&grid[4]==p&&grid[8]==p)
        return true;
    if(grid[2]==p&&grid[4]==p&&grid[6]==p)
        return true;
    return false;
}
void search(int t)
{
    if(wins('X'))
    {
        ans[grid]="the first player won";
        return;
    }
    else if(wins('0'))
    {
        ans[grid]="the second player won";
        return;
    }
    else if(t==9)
    {
        ans[grid]="draw";
        return;
    };
    if(t%2==0)
        ans[grid]="first";
    else
        ans[grid]="second";
    rep(i,9) if(grid[i]=='.')
    {
        grid[i]=t%2?'0':'X';
        search(t+1);
        grid[i]='.';
    }
}
int main()
{
    search(0);
    string s,t;
    rep(i,3)
    {
        cin>>t;
        s+=t;
    }
    if(ans.find(s)==ans.end())
        cout<<"illegal"<<endl;
    else
        cout<<ans[s]<<endl;
    return 0;
}

Codeforces Beta Round #85 (Div. 1 Only) C Petya and Spiders

翻译

给出一个\(n×m\)的网格,每个网格里有一只蜘蛛,每只蜘蛛一秒都可以向四个方向跳一格,不可以跳出网格(当然它也可以选择不跳)。问一秒之后(每只蜘蛛都行动至多一次)网格上有至多多少个位置没有蜘蛛。

思路

找到一个有蜘蛛的点,把这个蜘蛛能走的位置枚举
枚举到一个位置看看能不能把它旁边的蜘蛛移动过来

Code


/*
找到一个有蜘蛛的点,把这个蜘蛛能走的位置枚举
枚举到一个位置看看能不能把它旁边的蜘蛛移动过来
*/
#include<bits/stdc++.h>
using namespace std;
int neigh[5][2]= {{0,0},{1,0},{0,1},{-1,0},{0,-1}}; ///方向数组
/**
0 0 0,1//不动
1,0 0,1//x+1往右走一步 纵坐标不动
2,0 2,1//横坐标不动 往下走一步
3,0 3,1//往左走一步 纵坐标不动
4,0 4,1//横坐标不动 往上走一步
**/
int best,m,n;
int a[50][50];
void search(int x)
{
    int i,j,k,b1,x1,y1,xx,yy,x2,y2;
    vector< pair<int,int> > tmp;
    b1=0;
    for(i=0; i<m; i++)
    {
        for(j=0; j<n; j++)
            if(a[i][j]==0)///如果有蜘蛛
            {
                b1=1;
                break;
            }
        if(b1==1)
            break;
    }
    if(b1==0)///如果可以做到全没有
    {
        best=x;
        return ;
    }
    if(x+1>=best)///如果超过best,剪枝
        return ;
    xx=i;
    yy=j;///第一个有蜘蛛的位置
    for(k=0; k<5; k++)///k:五个方向
    {
        x2=xx+neigh[k][0];///尝试把这个蜘蛛上下左右走或不动
        y2=yy+neigh[k][1];
        if(x2>=0&&x2<m&&y2>=0&&y2<n) ///判断边界
        {
            tmp.clear();
            for(i=0; i<5; i++)
            {
                x1=x2+neigh[i][0];
                y1=y2+neigh[i][1];///再尝试每一个方向,这个蜘蛛周围还是否蜘蛛可以往这个点走
                if(x1>=0&&x1<m&&y1>=0&&y1<n&&a[x1][y1]==0) ///判断边界+有蜘蛛
                {
                    tmp.push_back(make_pair(x1,y1)); ///将x1下标,y1值添加到vector
                    a[x1][y1]=1;///标记无蜘蛛
                }
            }
            search(x+1);///继续下一步
            for(i=0; i<tmp.size(); i++)
                a[tmp[i].first][tmp[i].second]=0;///标记去除
        }
    }
}
int main()
{
    cin>>m>>n;
    memset(a,0,sizeof(a));
    best=m*n;
    search(0);
    cout<<m*n-best<<endl;
    return 0;
}

Codeforces Beta Round #80 (Div. 1 Only) B Cthulhu

翻译

给你 \(n\) 个点 \(m\) 条边的无向图(无重边和自环),问你是否存在一个简单的环且环上的点都是某棵树的树根。

思路

一道有思维但是代码简的题,要是你没有想明白,这就是一道简单但是也算的上坑的题,代码可能要上百行。那么让我讲解简单的方法。

如果一个图里有一个环,那么他的顶点数\(=\)边数。

然后看一下联通,既然是联通,那么一个点能到达的点和总点数一定相等。

Code

#include<bits/stdc++.h>
using namespace std;
int n,m,i,x,y,z;
vector <int> g[101];
bool u[1001];
void dfs(int i)
{
    u[i]=true; z++;
    for(int j=0;j<g[i].size();j++)
        if(!u[g[i][j]])
        dfs(g[i][j]);
}
int main()
{
    cin>>n>>m;
    for(i=0;i<m;i++)
    {
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    if(n!=m)
        return cout<<"NO"<<endl,0;
    dfs(1);
    if(z==n)
        cout<<"FHTAGN!"<<endl;
    else
        cout<<"NO"<<endl;
    return 0;
}

Codeforces Round #125 (Div. 1) B Jumping on Walls

翻译

一张\(n*2\)的图,\(X\)代表不可走,\(-\)代表可以走。一个忍者\((0,1)\)开始起跳,有三种跳的方法,向对面往上跳\(k\)步,向上或者向下跳一步,每跳一次,洪水就会往上涨一格,问这个忍者能否跳出这张图。

思路

深度优先搜索的水题,就是题意真难理解。本题只要标记走过了,就别打回来,否则一般会无限递归。我们判断是否走出悬崖的条件有:

  • 换一条路走\(k\)步出去了

  • 直接走一步出去了

不合法就是洪水淹了你,回溯。

Code

#include<bits/stdc++.h>
using namespace std;
char s[2][100005];
int vis[2][100005];
int n,k;
void dfs(int x,int y,int d)
{
    vis[x][y]=true;
    if(y+k>=n||y+1>=n)
    {
        puts("YES");
        exit(0);
    }
    if(d>=y)
        return ;
    if(s[!x][y+k]=='-'&&!vis[!x][y+k])
        dfs(!x,y+k,d+1);
    if(s[x][y-1]=='-'&&!vis[x][y-1]&&y-1>=0)
        dfs(x,y-1,d+1);
    if(s[x][y+1]=='-'&&!vis[x][y+1])
        dfs(x,y+1,d+1);
}
int main()
{
    int i,j;
    cin>>n>>k;
    cin>>s[0]>>s[1];
    dfs(0,0,-1);
    puts("NO");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lyfoi/p/9637340.html