2022.3.19

蓝书

AcWing 190. 字串变换

一开始用的是双向bfs,但只过了4个点,但是硬是要调,调了一下午还是没调出来。。后面换成普通bfs写发现也能过而且代码更少看来不能老是死磕,思路就是直接开队列按字符串的位置找能换的字串,如果最后换到和b一样说明成功了并且操作小于10说明成功了,否则输出-1。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100,INF=1e8;
string aa[10], bb[10];
string a, b;
int cnt;
struct node
{
    string x;
    int tt;
};
int bfs()
{
    if(a==b)
        return 0;
    queue<node> que;
    que.push({a, 0});
    while(que.size())
    {
        auto t = que.front();
        que.pop();
        string s = t.x;
        int tt = t.tt;
        if(tt>=10)
            return -1;
        for (int i = 0; i < cnt;i++)
        {
            int pos = s.find(aa[i],0);
            while(pos!=-1)
            {
                node t2;
                t2.x = s;
                t2.tt = tt + 1;
                t2.x.replace(pos, aa[i].size(), bb[i]);
                if(t2.x==b)
                {
                    return t2.tt;
                }
                que.push(t2);
                pos = s.find(aa[i], pos + 1);
            }
        }
    }
    return -1;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >>a>> b;
    while(cin>>aa[cnt]>>bb[cnt])
    {
        cnt++;
    }
    int ans = bfs();
    if(ans!=-1)
    {
        cout << ans << '\n';
    }
    else
        cout << "NO ANSWER!" << '\n';
    return 0;
}

AcWing 191. 天气预报

思路是枚举上下左右走1步还是2步九个状态,但是并不需要枚举每个格子是否超过一周没下雨,因为云是2x2的,也就是说云在的四个格子都会降雨,我们可以把四个格子看成是一个格子,这样只需要记录左上角的格子的状态就可以知道其他三个的状态,遍历的实时更新状态看是否合法,如果最后递归到了第n天说明是合法的。但是这题真的卡时间卡的离谱,t了不知道多少次,就算按题解的代码改了还是超时,其中注意一下记录状态的数组最好开bool,不然会爆内存,然后只有在里边循环的时候再把s1,s2,s3,s4写出来,写在循环外面会超时。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=365+10,INF=1e8;
bool vis[N][3][3][7][7][7][7];
int n,dx[9] = {0, 0, 0, 1, 2, 0, 0, -1, -2}, dy[9] = {0,-1, -2, 0, 0, 1, 2, 0, 0};
int a[N][5][5];
struct node
{
    int d, x, y, s1, s2, s3, s4;
};
bool check(int d,int x,int y)
{
    if(x >= 0 && x < 3 && y >= 0 && y < 3)
    {
        if(a[d][x][y]||a[d][x+1][y]||a[d][x][y+1]||a[d][x+1][y+1])
            return 0;
        else return 1;
    }
    return 0;
}
bool bfs()
{
    queue<node> que;
    que.push({1, 1, 1, 1, 1, 1, 1});
    vis[1][1][1][1][1][1][1] = 1;
    while(que.size())
    {
        auto t = que.front();
        que.pop();
        if(t.d==n)
            return 1;
        for (int i = 0; i < 9;i++)
        {
            int xx = t.x + dx[i], yy = t.y + dy[i];
            int d = t.d;
            if(!check(d+1,xx,yy)) continue;
            int s1=t.s1,s2=t.s2,s3=t.s3,s4=t.s4;
            if(xx==0&&yy==0)
            {
                s1 = 0;
            }
            else if(++s1==7)
                continue;
            if(xx==0&&yy==2)
            {
                s2 = 0;
            }
            else if(++s2==7)
                continue;
            if(xx==2&&yy==0)
            {
                s3 = 0;
            }
            else if(++s3==7)
                continue;
            if(xx==2&&yy==2)
            {
                s4 = 0;
            }
            else if(++s4==7)
                continue;
            if(vis[d+1][xx][yy][s1][s2][s3][s4])
                continue;
            vis[d + 1][xx][yy][s1][s2][s3][s4] = 1;
            que.push({d + 1, xx, yy, s1, s2, s3, s4});
            
        }
    }
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n&&n)
    {
        memset(vis, 0, sizeof vis);
        for (int i = 1; i <= n;i++)
        {
            for (int j = 0; j < 4;j++)
            {
                for (int k = 0; k < 4;k++)
                {
                    cin >> a[i][j][k];
                }
            }
        }
        if(bfs())
            cout << 1 << '\n';
        else
            cout << 0 << '\n';
    }
    return 0;
}

AcWing 195. 骑士精神

这道IDA咋看起来像bfs。对于本题我们可以换位思考,把问题转换成如何把输入的棋盘还原成原来的棋盘呢,我们现在找到当前可以移动的点,就是星点,然后枚举8个方向,直到两个棋盘相等,因为n范围只有15,所以我们可以使用迭代加深的方法,设定一个估价函数,一开始把估计函数设计成了当前的*点到原来棋盘星点的距离,发现超时了没设计好,于是看了题解的设计思路,估计函数设计成当前棋盘和原来棋盘不相等的点的个数。如果当前步数加上估价函数超过限制深度的话就回溯。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int dx[8] = {-1, -1, 1, 1, -2, -2, 2, 2}, dy[8] = {-2, 2, -2, 2, -1, 1, -1, 1};
char a[5][5]=
{'1','1','1','1','1',
'0','1','1','1','1',
'0','0','*','1','1',
'0','0','0','0','1',
'0','0','0','0','0'},b[5][5];
bool check()
{
    for (int i = 0; i < 5;i++)
        for (int j = 0; j < 5;j++)
        if(a[i][j]!=b[i][j])
            return 0;
    return 1;
}
int dis()
{
    int cnt = 0;
    for (int i = 0; i < 5;i++)
        for (int j = 0; j < 5;j++)
        {
            if(a[i][j]!=b[i][j]&&b[i][j]!='*')
                cnt++;
        }
    return cnt;
}
bool dfs(int dep,int cnt)
{
    if(cnt+dis()>dep)
        return 0;
    if(check())
        return 1;
    
    int x, y;
    for (int i = 0; i < 5 ;i++)
        for (int j = 0; j < 5;j++)
            if(b[i][j]=='*')
                x = i, y = j;
                
    for (int i = 0; i < 8;i++)
    {
        int xx = x + dx[i], yy = y + dy[i];
        if(xx<0||xx>=5||yy<0||yy>=5)
            continue;
        swap(b[xx][yy], b[x][y]);
        if(dfs(dep, cnt + 1))return 1;
        swap(b[xx][yy], b[x][y]);
    }
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while (t--)
    {
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < 5; j++)
                    cin >> b[i][j];

                    
        int dep = 0;
        while (dep <= 15)
        {
            if (dfs(dep,0))
                break;
            dep++;
        }
        if(dep<=15)
            cout << dep << '\n';
        else
            cout << -1 << '\n';
    }
    return 0;
}
posted @ 2022-03-19 18:48  menitrust  阅读(52)  评论(0编辑  收藏  举报