洛谷 题解 P1225 【黑白棋游戏】

看见很多dalao写了什么双向BFS,蒟蒻表示不会写啊。

怎么办办?

先来分析一下题目,一眼看去就是一个搜索题,考虑DFS与BFS。

先放一份DFS的代码:

#include<bits/stdc++.h>
using namespace std;
bool a[5][5],b[5][5];
char c;
int dx[5]={0,0,0,1,-1};
int dy[5]={0,1,-1,0,0};
int ans=0x3f3f3f3f;
int ax[110],bx[110],ay[110],by[110];
int ansx1[110],ansx2[110],ansy1[110],ansy2[110];
int cnt=0,ans_cnt;
map<string,int>mp;
inline string get()
{
    string s="";
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)s+=a[i][j]+'0';
    return s;
}
inline bool check()
{
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
            if(a[i][j]!=b[i][j])return 0;
    return 1;
}
inline void DFS(int x,int y,int tot)
{
    /*for(int i=1;i<=4;i++)
    {
        for(int j=1;j<=4;j++)cout<<a[i][j];
        cout<<endl;
    }
    cout<<tot<<endl;*/
    //Sleep(100);
    if(tot>=ans)return;
    if(check())
    {
        ans=tot;
        ans_cnt=cnt;
        for(int i=1;i<=cnt;i++)
        {
            ansx1[i]=ax[i];
            ansx2[i]=bx[i];
            ansy1[i]=ay[i];
            ansy2[i]=by[i];
        }
    }
    if(y==5)return;
    if(x==5)x=1,y++;
    /*string s=get();
    cout<<s<<endl;
    if(mp[s]<tot&&mp[s]!=0)return;
    mp[s]=tot;*/
    DFS(x+1,y,tot);
    for(int i=1;i<=4;i++)
    {
        int aa=dx[i]+x,bb=dy[i]+y;
        if(aa<1||aa>4||bb<1||bb>4||a[aa][bb]==a[x][y])continue;
        cnt++;
        ax[cnt]=x;ay[cnt]=y;
        bx[cnt]=aa;by[cnt]=bb;
        swap(a[aa][bb],a[x][y]);
        DFS(x+1,y,tot+1);
        cnt--;
        swap(a[aa][bb],a[x][y]);
    }
}
int main()
{
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            cin>>c;
            if(c=='1')a[i][j]=1;
            else a[i][j]=0;
        }
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            cin>>c;
            if(c=='1')b[i][j]=1;
            else b[i][j]=0;
        }
    DFS(1,1,0);
    cout<<ans<<endl;
    for(int i=1;i<=ans_cnt;i++)
    {
        cout<<ansx1[i]<<ansy1[i]<<ansx2[i]<<ansy2[i]<<endl;
    }
    return 0;
}

这里枚举每一个点,进行上下左右的交换。看上去很(fei)有(chang)道(che)理(dan)的样子,但是很明显,有时候交换完下面的点还可以去交换上面的点,所以有时候会搜不到答案,只能拿到60分

蓝题能拿60分也很不错了呢

怎么办办?

那么当然要用BFS啦,(蒟蒻不会记录方案的好办法,只能暴力存储啦)

#include<bits/stdc++.h>
using namespace std;
bool a[5][5],b[5][5];
char c;
int dx[5]={0,0,0,1,-1};
int dy[5]={0,1,-1,0,0};//上下左右
int ans=0x3f3f3f3f;
int ansx1[100],ansx2[100],ansy1[100],ansy2[100];
map<string,int>mp;//剪枝专用
struct Node
{
    bool cc[5][5];//记录当前局势
    int tot;//记录总数
    int x1[20],x2[20],y1[20],y2[20];//记录方案
};
inline void BFS()
{
    queue<Node>q;
    Node now;
    now.tot=0;
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
            now.cc[i][j]=a[i][j];//把局势copy一份
    q.push(now);
    while(q.size())
    {
        Node now=q.front();
        /*for(int i=1;i<=4;i++)
        {
            for(int j=1;j<=4;j++)cout<<now.cc[i][j];
            cout<<endl;
        }
        cout<<now.tot<<endl;*/
        q.pop();
        bool flag=1;
        for(int i=1;i<=4;i++)
            for(int j=1;j<=4;j++)if(now.cc[i][j]!=b[i][j])flag=0;
        if(flag)//找到答案
        {
            ans=now.tot;//更新答案
            for(int i=1;i<=ans;i++)
            {
                ansx1[i]=now.x1[i];
                ansx2[i]=now.x2[i];
                ansy1[i]=now.y1[i];
                ansy2[i]=now.y2[i];
            }//更新方案
            return;
        }
        string s="";
        for(int i=1;i<=4;i++)
            for(int j=1;j<=4;j++)s+=now.cc[i]
        //cout<<q.size()<<" "<<s<<" "<<mp[s]<<endl;
        if(mp[s]!=0&&mp[s]<=now.tot)continue;[j]+'0';//当前状态如果已经有更优解了,那就不用搜了(状态压缩的思想)
        mp[s]=now.tot;
        Node next;
        next.tot=now.tot+1;
        for(int i=1;i<=4;i++)
            for(int j=1;j<=4;j++)next.cc[i][j]=now.cc[i][j];//把方案copy一份(由于蒟蒻想不到好方法,还请dalao勿喷)
        for(int i=1;i<=now.tot;i++)
        {
            next.x1[i]=now.x1[i];next.y1[i]=now.y1[i];
            next.x2[i]=now.x2[i];next.y2[i]=now.y2[i];
        }
        for(int i=1;i<=4;i++)
        {
            for(int j=1;j<=4;j++)
            {
                for(int k=1;k<=4;k++)
                {
                    int aa=dx[k]+i;
                    int bb=dy[k]+j;
                    if(aa<1||bb<1||aa>4||bb>4||now.cc[i][j]==now.cc[aa][bb])continue;//超过边界或为相同数字,那么就continue
                    swap(next.cc[aa][bb],next.cc[i][j]);//交换
                    next.x1[next.tot]=i;next.y1[next.tot]=j;
                    next.x2[next.tot]=aa;next.y2[next.tot]=bb;//添加新方案
                    q.push(next);
                    swap(next.cc[aa][bb],next.cc[i][j]);//回溯
                }
            }
        }
    }
}
int main()
{
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            cin>>c;
            if(c=='1')a[i][j]=1;
            else a[i][j]=0;
        }
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            cin>>c;
            if(c=='1')b[i][j]=1;
            else b[i][j]=0;
        }
    BFS();
    cout<<ans<<endl;
    for(int i=1;i<=ans;i++)
    {
    	cout<<ansx1[i]<<ansy1[i]<<ansx2[i]<<ansy2[i]<<endl;
    }
    return 0;
}
posted @ 2019-06-20 09:30  hulean  阅读(367)  评论(0编辑  收藏  举报