陕西省集训 day4(搜索下)

本文解析了 CodeForces 平台上的多个题目,包括路径规划、矩阵操作、最短路径等算法问题,提供了详细的代码实现及解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A题:

http://codeforces.com/problemset/problem/540/C

题意:

从起始点到终止点走,’ . ‘表示裂的冰,‘X’表示已经碎了不能走了(起点可以),’ . ‘走过变成’ X ‘,最后要求这个人的末位置冰碎掉。

思路:

就是说最后末尾位置如果是’。’,要绕出去再回来踩碎它。。。当时读题半个小时QAQ

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int,int> pii;
queue<pii>q;

char s[510][510];
int stx,sty,enx,eny;
int n,m;
int vis[510][510];
int dir[4][2] = { {0,1},{-1,0},{1,0},{0,-1} };
int mp[4] = {1,2,3,4};
int bfs()
{
    pii ps = make_pair(stx-1,sty-1);
    q.push(ps);
    while(!q.empty())
    {
        pii tmp = q.front();
        q.pop();
        int tmx = tmp.first,tmy = tmp.second;
        if(vis[enx-1][eny-1] == 2)
            return 1;
        for(int i = 0 ; i < 4 ;i++)
        {
            int nox = tmx+dir[i][0];
            int noy = tmy+dir[i][1];
            if(nox >=0&&nox<n&&noy >=0&&noy <m &&s[nox][noy] =='.' &&!vis[nox][noy] || nox == enx-1&&noy == eny-1)
            {
                vis[nox][noy] ++;
           // cout << nox <<"  "<<noy <<endl;
                q.push(make_pair(nox,noy));
            }
        }
    }
    return 0;
}

int main()
{
    cin>> n >>m;
    for(int i = 0 ; i < n ;i++)
       {
            scanf("%s",s[i]);
            for(int j = 0 ; j < m;j++)
                if(s[i][j] == 'X')
                    vis[i][j]++;
       }
    cin >> stx>>sty>>enx>>eny;

        if(bfs())
            cout << "YES"<<endl;
        else
            cout <<"NO"<<endl;
    return 0;
}

B题:

题意:

两个人,一个从左上角到右下角,每次只能向下走或者向右走,另外一个人从右上角到左下角,只能向下或者向左,使得两条线路做经过的数字的和最大(交叉点的数字两条路线都不算进去)

思路:

从4个角分别向对角做dp,然后这样的话就可以得到每个点到4个角的最大值,接下来循环扫描每一个点作为交叉点,找出和最大的路径,但是到这里如果不加思考直接做的话就会出问题,因为对于不在边界上的任何一个点,从左上方来的话只能是从上方或者左方来,而从右上方来的话就会从这个点的上方和右方来,另外两个点也是如此,先分析这两个方向,他们有一个共同的来向,如果直接用当前点到4个角的最大值的和减去4倍的这个点的值,就有可能发生重叠,导致在这点之前路线就交叉了,显然不合题意,分析下来,交叉处只有两个选项,左上角的顶点从左方来,右下角的定点从右边来,或者是左上角的顶点从上方来,右下角的顶点从下方来,这是要注意的一个点,如果你分析了这一点的话,很容易知道边界点不可能是交叉点。

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1005

using namespace std;


int dp1[maxn][maxn],dp2[maxn][maxn],dp3[maxn][maxn],dp4[maxn][maxn];
int a[maxn][maxn];

int main()
{
    int n,m;
    cin >> n >>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            dp1[i][j] = max(dp1[i-1][j],dp1[i][j-1]) + a[i][j];
        }
    }

    for(int i=n;i>=1;i--)
    {
        for(int j=m;j>=1;j--)
        {
            dp2[i][j] = max(dp2[i+1][j],dp2[i][j+1]) + a[i][j];
        }
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=m;j>=1;j--)
        {
             dp3[i][j] = a[i][j] + max(dp3[i-1][j], dp3[i][j+1]);
        }
    }

    for(int i=n;i>=1;i--)
    {
        for(int j=1;j<=m;j++)
        {
            dp4[i][j] = a[i][j] + max(dp4[i][j-1], dp4[i+1][j]);
          //  cout << dp4[i][j] <<endl;
        }
    }


    int ans = 0;
    for(int i=2;i<n;i++)
    {
        for(int j=2;j<m;j++)
        {
            ans = max(ans,dp1[i-1][j]+dp2[i+1][j]+dp3[i][j+1]+dp4[i][j-1]);
            ans = max(ans,dp1[i][j-1]+dp2[i][j+1]+dp3[i-1][j]+dp4[i+1][j]);
        }
    }

    cout << ans <<endl;
    return 0;
}

C题:

题意:

从(1,1)走到(n,m),输入表示从(x1,y1)到 (x2,y2)需要第一把钥匙,0表示不需要,然后告诉你走到(x1,y1)处,你将得到哪个钥匙,可以多次使用,问最快什么时候走出去,不能走出去输出-1

思路:

钥匙怎么表示?一共最多9把,那么就可以用2进制表示这9把钥匙,0表示该位置上对应的第一把钥匙是没有的,1表示有,每次到了一个点(可能一个点有多把),把获得的钥匙相应位置标1,如果没有就接着搜索

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define maxn 55
using namespace std;
int dir[4][2] = { {0,1},{0,-1},{-1,0},{1,0} };
int r,c,k,n;
int path[maxn][maxn];
int door[maxn][maxn][maxn][maxn];
int key[maxn][maxn];
bool vis[maxn][maxn][1025];
typedef pair < pair<int,int>,int> pi3;
#define mp3(a,b,c) make_pair(make_pair(a,b),c)

int  bfs()
{
    queue<pi3> q;
    q.push(mp3(1,1,key[1][1]));
    path[1][1] = 0;
    memset(vis,0,sizeof(vis));

    while(!q.empty())
    {
        pi3 tmp = q.front();
        q.pop();
        int s1 = tmp.first.first;
        int s2 = tmp.first.second;
        int s3= tmp.second;
        if(s1 == r && s2 == c)
            return 1;
        for(int i = 0 ; i <4 ;i++)
        {
            //cout <<"asd" <<endl;
            int x = tmp.first.first+dir[i][0];
            int y = tmp.first.second+dir[i][1];
        //    cout <<"aa"<<r<<"  "<<c <<"  "<<x<<" " <<y <<" "<<vis[x][y][s3|key[x][y]]<<endl;
           if(x > 0 && x<=r && y >0 && y <= c && !vis[x][y][s3|key[x][y]]){
             //   cout <<"YES"<<endl;
                int z = s3|(key[x][y]);
//                cout <<"z = "<<z<<" dor   "<<s1<<" "<<s2<<" "<<x<< " " <<y <<"  "<<door[s1][s2][x][y]<<endl;
//                cout <<"sdf "<<(z >>(door[s1][s2][x][y]-1)&1)<<endl;
                if(door[s1][s2][x][y] == -1 || (door[s1][s2][x][y]&&(z >>(door[s1][s2][x][y]-1)&1) )){
               //     cout <<" YES"<<endl;
                    vis[x][y][z] = 1 ;
                    q.push(mp3(x,y,z));
                    path[x][y] = path[s1][s2]+1;
                //    cout << "  aaaa" <<x << "   "<<y<<"  " <<path[x][y]<<endl;
                }
           }
        }
    }
    return 0;
}

int main()
{
    int a,b,cc,d,dr,ky;
   while(cin >> r >>c >> k>>n) {
        memset(door,-1,sizeof(door));
        memset(key,0,sizeof(key));
       for(int i = 0 ; i < n ;i++){
           scanf("%d%d%d%d%d",&a,&b,&cc,&d,&dr);
           door[a][b][cc][d] = dr;
           door[cc][d][a][b] = dr;
       }
       int s;
       cin >> s;
       for(int i = 0 ; i < s ;i++){
            scanf("%d%d%d",&a,&b,&ky);
            key[a][b] |= 0|(1<<(ky-1));
       }
       if(bfs())
       cout << path[r][c]<<endl;

       else
        cout <<-1<<endl;
        //cout <<(0|(1<<(4-1)))<<endl;
   }


    return 0;
}

D题:

题意:

简单版推箱子、先保证推箱子走的距离最少,在保证人自己走的最少

思路:

搜索肯定是要搜了,这里注意,这个注意要bfs套bfs,就是说大方向是箱子决定方向,人呢,根据箱子要走的方向走到相应位置,比如箱子要往上走,那人就要走到他下面,左走在右等等,就可以保证了题意要求的

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int dir[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };
int vb[25][25],vp[25][25];
char s[25][25];
char pathb[5] = {'E','W','S','N'};
char pathp[5] = {'e','w','s','n'};
string tmp_ans= "";
int n,m,spx,spy,sbx,sby,enx,eny;
struct person
{
    int x, y;
    string path;
};

struct box
{
    int x,y;
    int px,py;
    string path;
};


int yy = 0;
int bfsp(int npx,int npy,int tox,int toy,int nbx,int nby)
{
    queue<person>qp;
    yy++;
    if(tox <0||tox>=n||toy <0 ||toy>=m)
        return 0;
    memset(vp,0,sizeof(vp));
    person tmp;
    tmp.x = npx,tmp.y = npy,tmp.path = "";
    qp.push(tmp);
    vp[tmp.x][tmp.y] = 1;
    while(!qp.empty())
    {
        person tmp = qp.front();
        qp.pop();
        if(tmp.x == tox && tmp.y == toy)
        {
//            if(yy == 2)
//                cout <<"   " <<tmp.x <<"   " <<tmp.y<<endl;
            tmp_ans = tmp.path;
            return  1;
        }
        for(int i = 0 ; i < 4; i++)
        {
            int nowx = tmp.x+dir[i][0];
           int nowy = tmp.y+dir[i][1];
           if(nowx >=0 &&nowx < n && nowy >=0 &&nowy < m && !vp[nowx][nowy] &&!(nowx == nbx&&nowy == nby) )
           {
               if(s[nowx][nowy] != '#')
               {
                   vp[nowx][nowy] = 1;
                   person tl;
                   tl.x = nowx,tl.y = nowy,tl.path = tmp.path+pathp[i];
                   qp.push(tl);
               }
           }
        }
    }
    return 0;
}

void bfsb()
{
    queue<box>qb;
    box sta;
    sta.x = sbx,sta.y = sby,sta.px = spx,sta.py = spy,sta.path = "";
   qb.push(sta);
   vb[sta.x][sta.y] = 1;
   while(!qb.empty())
   {
       box tmp = qb.front();
       qb.pop();
       if(tmp.x == enx && tmp.y == eny)
            cout <<tmp.path;
       for(int i = 0 ; i < 4 ;i++)
       {
           int nowx = tmp.x+dir[i][0];
           int nowy = tmp.y+dir[i][1];
           if(nowx >=0 &&nowx < n && nowy >=0 &&nowy < m && !vb[nowx][nowy])
           {
               if(s[nowx][nowy] !='#' && bfsp(tmp.px,tmp.py,tmp.x-dir[i][0],tmp.y-dir[i][1],tmp.x,tmp.y))
                    {
                        vb[nowx][nowy] = 1;
                        box t;
                        t.x = nowx,t.y = nowy,t.px = tmp.x,t.py = tmp.y,t.path = tmp.path+tmp_ans+pathb[i];
                        if(s[nowx][nowy] == 'T')
                        {
                            cout <<t.path<<endl;
                            return ;
                        }
                        else
                            qb.push(t);
                    }
           }
       }
   }
   printf("Impossible.\n");
}
int main()
{
    int Case = 0;
   while(~scanf("%d%d",&n,&m))
   {
       if(n == 0 && m ==0)
        break;
//    if(!qb.empty())
//        qb.pop();
//    if(!qp.empty())
//        qp.pop();
    printf("Maze #%d\n",++Case);
    for(int i = 0 ; i < n ;i++)
    {
        scanf("%s",s[i]);
        for(int j = 0 ; j < m ;j++)
            if(s[i][j] == 'S')
                spx = i,spy = j;
            else if(s[i][j] == 'B')
                sbx = i,sby = j;
            else if(s[i][j] == 'T')
                enx = i,eny = j;
    }
    memset(vb,0,sizeof(vb));
    bfsb();
    cout << endl;
   }
    return 0;
}

E题:

这题好难

题意:

两个小孩互相看不顺眼,要远离对方走,一个人不能经过另一个人的家或者学校,到了自己家或者学校之后不能在动了,两个人为了离对方最远可以循环走,不停地前后前后

思路:

普通的bfs上去掉vis数组,反正可以不断的重复走,队列维护这条路上两个人最近的那点的距离

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;

typedef pair< pair<int,int> , pair<int,int> > p4;
typedef pair< int , p4 > p5;

#define item1 first
#define item2 second.first.first
#define item3 second.first.second
#define item4 second.second.first
#define item5 second.second.second
#define mp2(a,b)       make_pair(a,b)
#define mp4(a,b,c,d)   make_pair(mp2(a,b),mp2(c,d))
#define mp5(a,b,c,d,e) make_pair(a,mp4(b,c,d,e))

const int MAXN = 33;
const int dir[4][2] = { {0,1},{-1,0},{0,-1},{1,0} };
const char sign[4] = {'E','N','W','S'};

char s[MAXN][MAXN];
int F[MAXN][MAXN][MAXN][MAXN];
p4 Last[MAXN][MAXN][MAXN][MAXN];
int n,m;
int hx,hy,Hx,Hy,sx,sy,Sx,Sy;

int dist(int x1,int y1,int x2,int y2){
    return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

void Out1( int x1 , int y1 , int x2 , int y2 ) {
    if (x1 == Hx && y1 == Hy && x2 == hx && y2 == hy) return;
    p4 tmp = Last[x1][y1][x2][y2];
    int x3 = tmp.first.first;
    int y3 = tmp.first.second;
    int x4 = tmp.second.first;
    int y4 = tmp.second.second;
    if ( x3 == x1 && y3 == y1 ) Out1(x3,y3,x4,y4);
    else {
        for ( int i = 0 ; i < 4 ; i ++ ) {
            if (x3 + dir[i][0] == x1 && y3 + dir[i][1] == y1) {
                Out1(x3,y3,x4,y4);
                printf("%c",sign[i]);
                break;
            }
        }
    }
}

void Out2( int x1 , int y1 , int x2 , int y2 ) {
    if (x1 == Hx && y1 == Hy && x2 == hx && y2 == hy) return;
    p4 tmp = Last[x1][y1][x2][y2];
    int x3 = tmp.first.first;
    int y3 = tmp.first.second;
    int x4 = tmp.second.first;
    int y4 = tmp.second.second;
    if ( x4 == x2 && y4 == y2 ) Out2(x3,y3,x4,y4);
    else {
        for ( int i = 0 ; i < 4 ; i ++ ) {
            if (x4 + dir[i][0] == x2 && y4 + dir[i][1] == y2) {
                Out2(x3,y3,x4,y4);
                printf("%c",sign[i]);
                break;
            }
        }
    }
}

void bfs()
{
    p5 x,y;
    int dis = dist(Hx,Hy,hx,hy);
    for ( int i = 0 ; i < n ; i ++ )
        for ( int j = 0 ; j < m ; j ++ )
            for ( int u = 0 ; u < n ; u ++ )
                for ( int v = 0 ; v < m ; v ++ )
                    F[i][j][u][v] = -1;
    F[Hx][Hy][hx][hy] = dis ;
    x = mp5(dis,Hx,Hy,hx,hy);
    priority_queue<p5> pq;
    pq.push(x);
    while(!pq.empty())
    {
        y = pq.top();
        pq.pop();
        if ( y.item2 == Sx && y.item3 == Sy && y.item4 == sx && y.item5 == sy ) break;

        for(int i = 0 ; i < 4; i++)
            for( int j = 0 ; j < 4 ; j ++)
            {
                int a = y.item2+dir[i][0];
                int b = y.item3+dir[i][1];
                int c = y.item4+dir[j][0];
                int d = y.item5+dir[j][1];
                if (y.item2 == Sx && y.item3 == Sy && y.item4 == sx && y.item5 == sy) continue;
                else if (y.item2 == Sx && y.item3 == Sy && (y.item4 != sx || y.item5 != sy)) {
                    a = y.item2;
                    b = y.item3;
                } else if ((y.item2 != Sx || y.item3 != Sy) && y.item4 == sx && y.item5 == sy) {
                    c = y.item4;
                    d = y.item5;
                }
                if(a >=0 && a<n && b >=0&&b<m &&c >=0&&c<n&&d>=0&&d<m && s[a][b] != '*'&&s[c][d] != '*' && s[a][b] != 'h' && s[a][b] != 's' && s[c][d] != 'H' && s[c][d] != 'S') {
                    int dis = min(dist(a,b,c,d),y.item1);
                    if ( dis > F[a][b][c][d] ) {
                        F[a][b][c][d] = dis;
                        Last[a][b][c][d] = mp4(y.item2,y.item3,y.item4,y.item5);
                        pq.push(mp5(F[a][b][c][d],a,b,c,d));
                    }
                }
            }
    }
    printf("%.2f\n",sqrt((double)F[Sx][Sy][sx][sy]));
    Out1( Sx , Sy , sx , sy ) ; printf( "\n" ) ;
    Out2( Sx , Sy , sx , sy ) ; printf( "\n" ) ;
}

int main(){
    while(~scanf("%d",&n) && n){
        m = n;
        for(int i = 0 ; i < n ;i++){
            scanf("%s",s[i]);
            for(int j = 0 ; j < n ;j++)
                if(s[i][j] == 'h') hx = i,hy = j;
                else if(s[i][j] == 'H') Hx = i ,Hy = j;
                else if(s[i][j] == 's') sx = i,sy = j;
                else if(s[i][j] == 'S') Sx = i,Sy = j;
        }
        bfs();
    }
    return 0;
}

F题:

题意:

从指定点走到指定点其中一写障碍,当走到那个点是k的倍数的时候就可以让那个障碍消失,其他时候就走不过

思路:

只有vis数组需要变一下,其他仍然是bfs最基础的思路,同一个点虽然可以走很多次,但是每次%k的值肯定是不同的,不然就是走了回头路
也可以把图形拓展为三维,每个点可以走到上一层或者下一层的左右前后,一个拓展k层,每一层上的每个点可以都是vis一次的=。=

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef pair <pair<int,int> ,int> pii;
#define mp3(a,b,c) make_pair( make_pair(a,b) ,c)
char s[110][110];
int path[110][110][10];
int vis[110][110][10];
int dir[4][2] = { {0,1},{0,-1},{1,0},{-1,0}};
int r,c,k;
int sx,sy,ex,ey;

void bfs()
{
    queue<pii> q;
    q.push(mp3(sx,sy,0));
    memset(path,0,sizeof(path));
    vis[sx][sy][0] = 1;
    while(!q.empty()){
        pii tmp = q.front();
        q.pop();
        if(tmp.first.first == ex && tmp.first.second == ey){
            cout << path[ex][ey][tmp.second] <<endl;
            return;
        }
        for(int i = 0 ; i < 4 ;i++){
            int x = tmp.first.first + dir[i][0];
            int y = tmp.first.second + dir[i][1];
            int z = (tmp.second +1)%k;
            if(x >= 0 && x < r && y >= 0 && y < c){
                if((s[x][y]=='.' || z == 0)&& !vis[x][y][z]){
                     vis[x][y][z] = 1;
                     path[x][y][z] = path[tmp.first.first][tmp.first.second][tmp.second]+1;
                     q.push(mp3(x,y,z));
                }
            }
        }
    }
    cout << "Please give me another chance!"<<endl;
}


int main()
{
    int T;
    cin >>T;
    while(T--){
      scanf("%d%d%d",&r,&c,&k) ;
      memset(vis,0,sizeof(vis));
      for(int i = 0 ; i < r ;i++){
          scanf("%s",s[i]);
          for(int j = 0 ; j < c ;j++)
            if(s[i][j] == 'Y'){
                sx = i,sy = j;
                s[i][j] = '.';
            }
            else if(s[i][j] == 'G'){
                ex = i,ey = j;
                s[i][j] = '.';
            }
      }
      bfs();
    }
    return 0;
}

G题:

作为一个搜索的题,可以用到小学数学公式开心么?

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

int gcd(int a,int b)
{
    return (b == 0)?a:gcd(b,a%b);
}
int main()
{
    int c,a,b;
    while(~scanf("%d%d%d",&c,&a,&b) )
    {
        if(a == 0 && b == 0 &&c == 0)
            break;
        int g = gcd(b,c);
        int c= a/g;
        int d = b/g;
        if((a+b)/g%2)
            cout << "NO\n";
        else
            cout << (c+d-1)<<endl;

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值