[kuangbin带你飞]专题一 简单搜索 回顾总结

  第二题:bfs,忘了将queue清空。

  第三题:bfs,记得使用vis数组,防止重复入队

  第三题:bfs会MLE。DFS只需使用到long long的19位长度即可。

      分析:

      BFS显然会按照2^N增长;还没找到答案之前内存就爆炸了。

      至于为什么可以用long long解决,不说前人探索出来的规律。你想想,如果是暴力搜索DFS,如果答案真得可能会到100位,那就会超出时间限制,所以位数不会太长。

      但要是超过了19位呢?那就用结构体来模拟除法咯,不过还是要用DFS。

  第四题:

      处在简单搜索这个题目集里面真是刺激到我了,所以人有点浮躁。然后还打游戏,精神不好,出了很多错误。所以,认真对待,用最好的面貌去迎接挑战。

        
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define maxn 25
#define sc scanf
#define pt printf
#define rep(i,a,b) for(int i=a;i<b;++i)
int a[maxn][maxn],op[maxn][maxn],out[maxn][maxn];
int m,n,cnt,ans;
--op的核心是如果上面的位置是黑色,那么他就应该是为1.
--但是,很简单的话语,包含了这个意思:
你可以省去了对a源数组的临时复制,只需要考虑周边产生的操作以及原位置的数值即可得到当前的op值
int main()
{
    #ifdef WANGNINGLOCAL
        freopen("in.txt","r",stdin);
    #endif 
    --这个是没有必要的,因为全局数组声明的时候未初始化,自动填充0.
    --而且,根本不会用到出界的a数组。
    --所以是逼急了的情况下抓的无用的稻草。
    memset(a,0,sizeof(a));
    while(~sc("%d%d",&n,&m))
    {
        ans=0x3f3f3f3f;
        rep(i,1,n+1) rep(j,1,m+1) sc("%d",&a[i][j]);
        rep(b,0,1<<m)
        {
            //pt("当前用于分解的二进制对象是 %d
",b);
            memset(op,0,sizeof(op)); cnt=0;
            for(int i=m;i>=1;--i)
            {
                --考虑到字典序最小,所以将从右往左赋最低到最高位。
                op[1][i] = (b>>(m-i))&1;
                //pt("在填第%d位,内容是%d
",i,op[1][i]);
                cnt += op[1][i];
            } 
            rep(i,2,n+1)
            {
                rep(j,1,m+1)
                {
                    int jg = a[i-1][j] + op[i-1][j] + op[i-1][j-1] + op[i-1][j+1];
                    if(i>=3) jg+=op[i-2][j];
                    if(jg%2==1)
                    {
                        op[i][j]=1;
                        --这里是一个大错误,之前把上面的代码复制下来,那实际上完全就不应该用op[1][i]来在这里累加cnt
                        cnt += op[i][j];
                    }
                }
            }
            int i;
            for(i=1;i<=m;++i)
            {
                int jg = a[n][i] + op[n][i] + op[n][i-1] + op[n][i+1] +op[n-1][i];
                if(jg%2==1) break;
            } 
            if(i==m+1)
            {
                if(cnt<ans) {
                    ans=cnt;
                    memcpy(out,op,sizeof(op));
                }
            }
        }
        if(ans==0x3f3f3f3f) pt("IMPOSSIBLE
");
        else
        {
            --这里都是错误,因为之前没有写else语句。
            rep(i,1,n+1) rep(j,1,m+1) pt("%d%c",out[i][j]," 
"[j==m]);
        }
        
    }
    
    return 0;
}
View Code

       回过头来修改的自己最初的代码版本,里面居然纠正出了五个错误

        
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#include<vector>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define maxn 25
#define rep(i,a,b) for(int i=a;i<b;++i)
#define ull unsigned long long 
#define pb push_back
int R,C,i,j,x,k,mi,who,now;
int mp[maxn][maxn];
int cp[maxn][maxn];
int main()
{
    --大致思路:对cp二维数组进行实际的值的修改来模拟过程
    --第一行是要直接复制mp的内容的,接下来的R-1行会在动态修改的过程中逐行调用mp源数组的值
    --接下来会说说自己主要错在哪
    #ifdef WANGNINGLOCAL
        freopen("in.txt","r",stdin);
    #endif 
    while(~scanf("%d%d",&R,&C))
    {
        for(i=1;i<=R;++i) for(j=1;j<=C;++j) sc("%d",&mp[i][j]);
        mi=inf; who=-1;
        for(i=0;i<1<<C;++i)
        {
            //pt("i=%d!!!
",i);
            now=0;
            x=i;
            for(j=1;j<=C;++j) cp[1][j] = mp[1][j];
            for(j=C;j>=1;--j)
            {
                cp[1][j]=(x&1)^cp[1][j];
                cp[1][j+1]=(x&1)^cp[1][j+1];
                cp[1][j-1]=(x&1)^cp[1][j-1];
                cp[2][j]=(x&1)^mp[2][j];
                now+=(x&1);
                x=x>>1;
            }
            //你要搞懂,cp存的是什么
            //第一行放的是修改后的值,第二行及以后放的是修改后的值
            for(j=2;j<=R;++j)
            {
                for(k=1;k<=C;++k)
                {
                    //pt("%d%c",cp[j-1][k]," 
"[k==C]);
                    if(cp[j-1][k]==1)
                    {
                        ++now;
                        cp[j][k]=!cp[j][k];
                        cp[j][k-1]=!cp[j][k-1];
                        cp[j][k+1]=!cp[j][k+1];
                        cp[j+1][k]=!mp[j+1][k];
                    }
                    else cp[j+1][k]=mp[j+1][k];
                }
            }
            //判断依据是如果所有的操作都完毕后,最后一行如果有1值出现,那么方案不成立
            for(j=1;j<=C;++j)
            {
                //pt("%d%c",cp[R][j]," 
"[j==C]);
                if(cp[R][j]==1) break;
            } 
            if(j==C+1)
            {
                if(now<mi)
                {
                    mi=now; 
                    who=i;
                }
            }
        }
        if(who==-1) pt("IMPOSSIBLE
");
        else
        {
            //pt("%d %d
",who,mi);
            for(j=1;j<=C;++j) cp[1][j] = mp[1][j];
            //for(k=1;k<=C;++k)  pt("%d%c",cp[1][k]," 
"[k==C]);
            --错误点1:输出顺序必有先后,但是我从末位开始取值输出就错了。
            --错误点2:j还是从C到1,但是第一位取出来的异或值用在了最后一位上,第二位用在了倒数第二位上
                        也就是说输出顺序与操作顺序反了
            --错误点3:异或值整体是(who>>(C-j))&1,但是下面用成了who>>(C-j),可能以为右移了就只剩下那一位了吧
            for(j=1;j<=C;++j)
            {
                pt("%d%c",  (  who>>(C-j)  )&1," 
"[j==C]);
                cp[1][j]=(  (  who>>(C-j)  )&1  )^cp[1][j];
                cp[1][j+1]=(  (  who>>(C-j)  )&1  )^cp[1][j+1];
                cp[1][j-1]=(  (  who>>(C-j)  )&1  )^cp[1][j-1];
                cp[2][j]=(  (  who>>(C-j)  )&1  )^mp[2][j];
            }
            //for(k=1;k<=C;++k)  pt("%d%c",cp[1][k]," 
"[k==C]);
            for(j=2;j<=R;++j)
            {
                for(k=1;k<=C;++k)
                {
                    if(cp[j-1][k]==1)
                    {
                        pt("%d%c",1," 
"[k==C]);
                        cp[j-1][k]=0;
                        cp[j][k]=!cp[j][k];
                        cp[j][k-1]=!cp[j][k-1];
                        cp[j][k+1]=!cp[j][k+1];
                        cp[j+1][k]=!mp[j+1][k];
                    }
                    --错误点5:没有执行cp[j+1][k]=mp[j+1][k]操作
                    else
                    {
                        cp[j+1][k]=mp[j+1][k];
                        pt("%d%c",0," 
"[k==C]);
                    } 
                }
            }
        }
        
    }
    return 0;
}
View Code

   第五题: 使用了BFS,思路是先找出1000~9999之间的质数,然后对每个这样的质数寻找变动一位后的所有数,用map<int, vector<int> > nei 记录下来

       之后对每个输入的起点数,只要用结构体

        typedef struct nod{
          int what,dis;
        }nod;

        what代表到了哪个数,dis表示走了几步,使用BFS就行了。

      注意点:

      1.仍旧是queue的清空问题——虽然这回我是没有在上面犯错的,但依旧觉得很重要。

      2.vis数组使用了,时间在0.3秒; 没用使用,时间在2.4秒。 —— 仅从样例来看。

          所以,走过的路,已经有人走过了,就不用再走,不论前方是成功还是失败,成功了果实不是你的,因为你的dis比别人的大,也就是来得晚了;

         别人如果失败了,那你干嘛要走呢?另寻他途吧。

       

        
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#include<vector>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define maxn 10005
#define rep(i,a,b) for(int i=a;i<b;++i)
#define ull unsigned long long 
#define pb push_back
#define ull unsigned long long

int vis[maxn];
int isprime[maxn];
vector<int> pri;
map<int, vector<int> > nei;
typedef struct nod{
    int what,dis;
}nod;
queue<nod> q;
nod ob,now;
int mypow(int a,int b)
{
    int ret = 1;
    rep(i,0,b) ret*=a;
    return ret;
}
void findnei(int who,int ra) //ra是倒数第几位
{
    int i,j,k,x;
    int sum=0,po;
    for(i=3;i>=0;--i)        //i=2时,是百位,但是是倒数第三位。
    {
        if(i==ra-1) continue; 
        sum+=mypow(10,i)*(who/mypow(10,i)%10);
    }
    for(i=0;i<=9;++i) 
    {
        x=sum+i*mypow(10,ra-1);
        if(x!=who&&isprime[x]==0) nei[who].pb(x);
    }
}
int main()
{
    
    #ifdef WANGNINGLOCAL
        freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
    #endif 
    memset(isprime,0,sizeof(isprime)); // --1 不是prime
    
    int T,n,m,i,j,k,x,y,z,cnt;
    /*获取质数*/
    for(i=2;i<maxn;++i)
    {
        if(isprime[i]==0)
        {
            if(i>=1000&&i<=9999) pri.pb(i); //只要四位数字级别的
            for(j=i*i;j<maxn;j+=i) isprime[j]=1;
        }
    }
    /*下面将只相差一位且为质数的数字压入*/
    for(i=0;i<(int)pri.size();++i)
    {
        //千位不同
        x=pri[i];
        y=x%1000;
        for(j=1;j<=9;++j)
        {
            z=j*1000+y;
            if(isprime[z]==0 && z!= x) nei[x].pb(z);
        } 
        //百位不同
        for(j=1;j<=3;++j) findnei(x,j);
    }
    sc("%d",&T);
    while(T--)
    {
        sc("%d%d",&n,&m);
        while(!q.empty()) q.pop();
        memset(vis,0,sizeof(vis));
        vis[n]=1; cnt=0;
        ob.dis=0; ob.what=n;
        q.push(ob);
        while(!q.empty())
        {
            now=q.front(); q.pop();
            if(now.what==m) break;
            ob.dis=now.dis+1;
            rep(i,0,(int)nei[now.what].size())
            {
                z= nei[now.what][i];
                if(!vis[z])
                {
                    ob.what = z;
                    vis[z]=1;
                    q.push(ob);
                }
                
            }
        }
        if(now.what==m) pt("%d
",now.dis);
        else pt("Impossible
");
    }
    return 0;
}


/*
    //看看对不对
 
    对的
    for(i=0;i<(int)pri.size();++i)
    {
        //千位不同
        x=pri[i];
        pt("x=%d
",x);
        for(j=0;j<(int)nei[x].size();++j)
        {
            pt(":)  %d%c
",nei[x][j]," 
"[j==(int)nei[x].size()-1]);
        }
        //百位不同
        for(j=1;j<=3;++j) findnei(x,j);
    }
 */
View Code

   第六题:数组大小开错了,要注意合并的长度会达到2*C。

        
#include<cstdio>
#include<cstring>
#include<set>
#include<cstring>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define maxn 105
int main()
{
    set<string> s;
    #ifdef WANGNINGLOCAL
        freopen("in.txt","r",stdin);
    #endif 
    int T,len,i,run=0,cnt;
    string ob;
    char a[maxn],b[maxn],tar[2*maxn],cp[2*maxn];
    sc("%d",&T);
    while(T--)
    {
        for(i=0;i<maxn;++i) a[i]=b[i]=tar[i]=cp[i]='';
        s.clear();  cnt=0;
        sc("%d",&len);
        sc("%s%s%s",a,b,tar);
        while(1)
        {
            ++cnt;
            for(i=0;i<len;++i)
            {
                cp[i*2] = b[i]; 
                cp[i*2+1] = a[i]; 
             } 
            if(strcmp(cp,tar)==0) break;
            ob=cp;
            if(s.find(ob)!=s.end())
            {
                cnt=-1;
                break;
            }
            else
            {
                s.insert(ob);
                for(i=0;i<len;++i)
                {
                    a[i] = cp[i] ; 
                    b[i] = cp[i+len] ; 
                } 
            }
        }
        
        pt("%d %d
",++run,cnt);
    }
    return 0;
}
View Code

   第七题:总结和思路放在代码里

        
#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define maxn 105 
/*
思路:
使用BFS,对六种操作依次压入。然后取出后执行{
    将当前操作压入操作路径;
    根据操作类型修改值;
    判断修改后的值之前是否得到过: 未得到过——在此基础上压入六种操作, 否则——不处理 ;
    判断修改后的值是否有等于C的值,有则退出; 
} 
注意点: 
POUR的解读:要么把j倒满,要么把i倒完,但是不会有浪费
使用了set来代替vis,实际上由于A B C都在1~100之间,所以可以用二维的vis处理。
第一次测试样例没过,因为在AB之间倒水的环节,先执行了清零才进行将水倒给另外一个罐子的操作。       
第一发没过,因为没有处理impossible的情况。 
*/
typedef struct st{
    int a,b;
    bool operator < (const st &x)const
    {
        if(a==x.a)
            return b<x.b;
        else
            return a<x.a;
    }
}st;
typedef struct ob{
    char now;
    string way;
    st g;
}ob;
ob op;
queue<ob> q;
set<st> s;
int A,B,C,diff,i,len,flag=0;
void myadd()
{
    op.now='0'; q.push(op);//"111"
    op.now='1'; q.push(op);//"122"
    op.now='2'; q.push(op);//"211"
    op.now='3'; q.push(op);//"222"
    op.now='4'; q.push(op);//"312"
    op.now='5'; q.push(op);//"321"
}
int main()
{
    #ifdef WANGNINGLOCAL
        freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
    #endif 
    sc("%d%d%d",&A,&B,&C);
    op.way=""; op.g.a=0; op.g.b=0;
    myadd();
    while(!q.empty())
    {
        op=q.front(); q.pop();
        op.way+=op.now;
        switch(op.now){
            case '0':{
                op.g.a=A;
            };break;
            case '1':{
                op.g.b=B;
            };break;
            case '2':{
                op.g.a=0;
            };break;
            case '3':{
                op.g.b=0;
            };break;
            case '4':{
                diff = B - op.g.b;
                if(op.g.a >= diff) {
                    op.g.b = B;
                    op.g.a -= diff;
                }
                else{
                    op.g.b += op.g.a;
                    op.g.a = 0;
                }
            };break;
            case '5':{
                diff = A - op.g.a;
                if(op.g.b >= diff) {
                    op.g.b -= diff;
                    op.g.a = A;
                }
                else{ //这里出过错,因为b清零了不能再把原来预定的水资源给a 
                    op.g.a += op.g.b;
                    op.g.b = 0 ;
                    
                }
            };break;
        }
        if(s.find(op.g)==s.end()){
            s.insert(op.g);
            myadd();
        }
        if(op.g.a==C||op.g.b==C)
        {
            flag=1;    
            break;
        } 
    }
    if(flag==0) {
        pt("impossible
");
        return 0;
    }
    len = op.way.length();
    pt("%d
",len);
    for(i=0;i<len;++i)
    {
        switch(op.way[i]){
            case '0':pt("FILL(1)
");break;
            case '1':pt("FILL(2)
");break;
            case '2':pt("DROP(1)
");break;
            case '3':pt("DROP(2)
");break;
            case '4':pt("POUR(1,2)
");break;
            case '5':pt("POUR(2,1)
");break;
        }
    }
    return 0;
}
View Code

   第八题:错误回顾和关键点放在代码里。

   思路就是BFS,选定两个点,然后往四周扩散,如果烧过了就不管,否则就将其压入queue,并且其状态置为烧过了。

        
#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define maxn 15
#define inf 0x3f3f3f3f
int T,N,M,cnt,tot,ans,out;
char a[maxn][maxn],b[maxn][maxn];
int dix[4]={1,-1,0,0};
int diy[4]={0,0,1,-1};
typedef struct ob{
    int x,y,dis;
}ob;
ob op,tp;
queue<ob> q;
int test_set(ob z)
{
    if(z.x<0||z.x>=N||z.y<0||z.y>=M||b[z.x][z.y]!='#') return 0;
    else
    {
        b[z.x][z.y]='.';    
        q.push(z);
        ans=max(ans,z.dis);
        return 1;
    }
}
错误回顾
1.字符串数组开成一维的了
2.z.y>=M 写成了z.x>=M
3.中间为了节省时间,我使用了:{
    如果上一轮选的点都不是干草堆,那么下一次就不用再让a复制给b。
}的操作,但是问题在于,{
    对应的变量是mytri,mytri会在cnt大于0的时候置1,cnt大于0代表选的点有干草堆。
    mytri的作用是,如果是1,那么代表需要将a复制给b; 
        如果是0,那么代表之前最初选取的两个点都不是干草堆,所以就没有对b做出修改,所以就可以沿用此次的复制值(来自整个a),所以这样可以节省复制的时间。
        但是最大的问题是:一开始你一定要将它设置为1,因为b总要有第一次的复制过程吧。
        那你一开始是要给他赋初值1的。
        这样想是对的,关键是,设置为1的位置放错了。
        你想想,b第一次要获取a的值,是在a有值了之后,而每次a什么时候会更新呢? 
        每个test case都会有新的进来啊。
        所以说,如果我们在上一个case的最后阶段,没有成功的选取到非干草堆的情况,那么mytri会是0,
        而mytri=1被我放在了while(T--)前面了,所以会出错。
        就那样例来说,我这样的处理方式最后是同时选取了最后一个点,而最后一个点是'.'——非干草堆,所以出现了下一轮b没有被a初始化的错误。
}
关键点:
ans是每次搜索之后,当前的最远的距离(火烧到这个grid经历的grid数)
    由于每次搜索是N*M中的两个点,所以每次选定两个点之后都要重新置零。
out是搜索成功的最短路径值,所以一开始要设置成inf那么大

int main()
{
    #ifdef WANGNINGLOCAL
        freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
    #endif
    int i,j,k,mytri=1,run=0,dec;
    sc("%d",&T);
    while(T--)
    {
        mytri=1;
        dec = 0;
        out = inf;
        sc("%d%d",&N,&M); getchar();
        tot=0;
        memset(a,'',sizeof(a)); memset(b,'',sizeof(b));
        for(i=0;i<N;++i){
            sc("%s",a[i]);
            for(j=0;j<M;++j) if(a[i][j]=='#') ++tot;
        } 
        for(i=0;i<N*M;++i)
        {
            for(j=i;j<N*M;++j)
            {
                cnt=ans=0; 
                while(!q.empty()) q.pop();

                if(mytri==1)  memcpy(b,a,sizeof(a));
                
                op.dis=0;
                op.x=i/M; op.y=i%M; 
                cnt += test_set(op);
                op.x=j/M; op.y=j%M;
                cnt += test_set(op);
                if(cnt>0) //有可以纵火的点
                {
                    mytri=1;
                    while(!q.empty())
                    {
                        op=q.front();  q.pop();
                        tp.dis = op.dis + 1;
                        for(k=0;k<4;++k)
                        {
                            tp.x = op.x + dix[k];
                            tp.y = op.y + diy[k];
                            cnt += test_set(tp);
                        }
                        if(cnt==tot)
                        {
                            dec = 1;
                            out = min( out, ans ) ;
                            break;
                        } 
                    } 
                }
                else
                {
                    mytri = 0;
                }
            }
        }
        pt("Case %d: %d
",++run,dec==1?out:-1);
    }
    return 0;
}
View Code

   第九题:BFS,要特别注意更新火场情况的部分。

  思路和注意事项都放在代码里面,最后出错的部分我用--标记了,而不是//。

  所以你复制了我的代码之后,直接编译,就能看到是在哪一行出错的。

  ……当然能AC了吧……UVA崩掉了的说,我交一发看看。

  ……TLE。让我改改。2019年5月4日15:52:19

  嗯,改出来了,结果是Joe走迷宫的时候,没有处理已经走过的情况,最终导致了TLE。所以我在Joe走迷宫的时候,对走过的点设置成了'J'。

  看别人的代码,虽然很多是细枝末节的,但是也学到了许多。

  首先,判断的规则最好简单明了,参考程序在判断的时候用了很多if-continue; 你感觉多,你感觉人家笨,你感觉你可以用一句话概括……但是之后查错的时候,简洁明了的if-continue真的可以很方便理解——查错的时候脑子往往很乱——今天很乱,乱了好几天了……——所以一定要简洁方便阅读。

  而且判断有没有走过,其实可以直接用vis来处理。

  下面贴出的代码,是能ac的,我知道确定起始点后把那个点的位置上的字符改成'.'没有必要的,fire_test函数有返回值也是没有必要的。

  但是就贴在那里吧,我不改了。

  最有意思的想法是我会根据时间来动态更新火场情况。

        
#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define maxn 1005
#define inf 0x3f3f3f3f
/*思路蛮简单的,维护两个queue,
一个关于火场的,这个要配合 {
    将输入的maze作相应的修改
} 操作
一个是关于joe的,对他当前可以去的square进行入队,当他已经在边界之外了,那么就可以结束了,
这个要配合{
    出界的情况反而是可以终止 while(!q.empty()) 的break条件
    观察四周可用的square
    变量flag,来预防特殊情况:如果当qj空了,还没有逃出火场+迷宫,那么就输出IMPOSSIBLE
}*/
char a[maxn][maxn];
int dix[4] = {1, -1, 0, 0};
int diy[4] = {0, 0, 1, -1};
int R, C;
typedef struct ob {
    int x, y, dis;
} ob;
ob op, tp, fire, adj;
queue<ob> q;  //获取Joe在dis时刻所在的位置
queue<ob> f;  //获取火焰在dis时刻所在的位置
int test_set(ob z)
{
    if (a[z.x][z.y] =='.' && (z.x <= 0 || z.x >= R-1 || z.y <= 0 || z.y >= C-1) ) 
        return 2;    //表明走出边界了
    else if (a[z.x][z.y] == '#' || a[z.x][z.y] == 'F'|| a[z.x][z.y] == 'J') return 0;
    else {
        a[z.x][z.y] = 'J' ; 
        q.push(z);
        return 1;
    }
}
int fire_test_set(ob z)
{
    if (z.x < 0 || z.x >= R || z.y < 0 || z.y >= C || a[z.x][z.y] == 'F' || a[z.x][z.y] == '#') 
        return 0;
    else
    {
        f.push(z);
        a[z.x][z.y] = 'F' ;
        return 1;
    }
}
/*哇,我居然在提前写总结
本意是为了不走重复的路,直接将所在位置置为墙壁,但是这样是不行的,
因为火有可能蔓延到你那个位置。
所以要用vis数组——不如直接在a数组的基础上修改,变成火了就标成'F'。
……这好像就是应该这样的。
而且为了判断的方便——没必要判断是'J'还是'.','J'本质上就是'.',只不过Joe刚好从那里出发而已。
所以应该将J所在位置探明后,就将其变成'.'。
火的dis也是有必要记录的,你不能一次性让f pop+push把整个迷宫都点燃吧?*/
int main()
{
#ifdef WANGNINGLOCAL
    freopen("in.txt", "r", stdin);
    //freopen("out.txt","w",stdout);
#endif
    int T, pre; //pre用来存储dis——如果现在出来的dis和之前的不一样了,那么代表已经进入了下一秒
    sc("%d", &T);
    while (T--)
    {
        while (!q.empty())  q.pop();
        while (!f.empty())  f.pop();
        sc("%d%d", &R, &C);
        int i, j, flag = 0, explore=1, state;
        op.dis = 1;
        for (i = 0; i < R; ++i)
        {
            sc("%s", a[i]);
            //如果没有找到起始位置,那么就特地判断一遍有没有包含J。
            for (j = 0; j < C; ++j) {
                if (a[i][j] == 'F') {
                    op.x = i; op.y = j;  f.push(op);
                }
                else if (explore && a[i][j] == 'J') {
                    op.x = i; op.y = j;  q.push(op);
                    explore = 0;
                    a[i][j] = '.' ;
                }
            }
        }
        op = q.front(); q.pop();
        if( test_set(op)==2 ) {
            pt("%d
", 1);
            continue;
        }
        //pre是用来更新火场情况的变量,它的值是dis时刻值。
        //如果我们发现当前的dis是新的时刻了,那么就会将新的时刻赋值给pre
        //然后更新新的火场情况
        pre = 1;
        while (!q.empty())
        {
            op = q.front(); q.pop();
            tp.dis = op.dis + 1;
            if (pre != tp.dis) {
                pre = tp.dis;
                //更新火场情况的语句块
                while (!f.empty()) {
                    fire = f.front();
                    //我们是希望得到这一秒的火场情况
                    //所以我们要的是上一秒的火场情况,即火焰的fire.dis时刻值<当前时刻
                    //--之前的错误就是写成了  if (fire.dis > pre ) break; 
                    if (fire.dis >= pre ) break; 
                    //如果是上一秒的,那么就pop
                    f.pop();
                    adj.dis = fire.dis + 1;
                    for (i = 0; i < 4; ++i)
                    {
                        adj.x = fire.x + dix[i];
                        adj.y = fire.y + diy[i];
                        fire_test_set(adj);
                    }

                }
            }
            //冷静观察火场,寻找逃生之路
            for (i = 0; i < 4; ++i)
            {
                tp.x = op.x + dix[i];
                tp.y = op.y + diy[i];
                state =  test_set(tp) ;
                if (state == 2) //能逃出火场
                {
                    flag = 1;
                    break;
                }
            }
            if (flag) break;
        }
        if (flag) pt("%d
", tp.dis);
        else       pt("IMPOSSIBLE
");
    }
    return 0;
}
View Code

   第十题:难度突然降下来了。但是犯的错是——没有将符合条件的对象push进queue。

      开始想到了vis,但是后来没有写;

      输出结果的时候,没有按照最初的想法,i是要小于输出序列的一半的

      ——注意力,专心点

        
#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define maxn 15
#define inf 0x3f3f3f3f
int dir[][2]={{0,1},{0,-1},{1,0},{-1,0}};
int vis[maxn][maxn],a[maxn][maxn];
typedef struct ob{
    string s;
    int x,y;
}ob;
ob op,tp;
int main()
{
#ifdef WANGNINGLOCAL
    freopen("in.txt", "r", stdin);
    //freopen("out.txt","w",stdout);
#endif
    int i,j,k;
    memset(vis,0,sizeof(vis));
    for(i=0;i<5;++i) for(j=0;j<5;++j) sc("%d",&a[i][j]);
    op.x=0; op.y=0; op.s="00";  vis[0][0] = 1;
    queue<ob> q;
    q.push(op);
    while(!q.empty())
    {
        op = q.front(); q.pop();
        if(op.x==4 && op.y == 4) break;
        tp.s = op.s;
        for(i=0;i<4;++i)
        {
            j = tp.x = op.x + dir[i][0];
            k = tp.y = op.y + dir[i][1];
            if(j<0||j>4||k<0||k>4) continue;
            if(a[j][k] == 1) continue;
            if(vis[j][k]==1) continue;
            tp.s +=  (char)( '0' + j ); 
            tp.s +=  (char)( '0' + k );
            vis[j][k] = 1;
            q.push(tp);
        }
    }
    for(i=0;i<(int)op.s.length()/2;++i)
    {
        pt("(%c, %c)
",op.s[i<<1],op.s[i<<1|1]);
    }
    return 0;
}
View Code

   第十一题:嗯,难度很低。就是加上了四个方向。

  BFS=dir[][2] + vis[][] +         a[][] +                  queue +                  清晰的规则理解 + 正确的细节处理

    怎么走     走过没  里面有什么内容 BFS本身需要的数据结构            人应该有的素质

#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define maxn 105
#define inf 0x3f3f3f3f
int dir[][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,-1},{-1,1}};
int vis[maxn][maxn];
char a[maxn][maxn];
typedef struct ob{
    int x,y;
}ob;
int R,C;
ob op,tp;
queue<ob> q;
int main()
{
#ifdef WANGNINGLOCAL
    freopen("in.txt", "r", stdin);
    //freopen("out.txt","w",stdout);
#endif
    while(sc("%d%d",&R,&C)&&R)
    {
        int i,j,k,tx,ty,cnt;
        for(i=0;i<R;++i) sc("%s",a[i]);
        memset(vis,0,sizeof(vis));
        while(!q.empty()) q.pop();
        cnt=0;
        for(i=0;i<R;++i)
        {
            for(j=0;j<C;++j)
            {
                if(!vis[i][j]&&a[i][j]=='@')
                {
                    ++cnt;
                    vis[i][j] = 1;
                    op.x = i; op.y = j; 
                    q.push(op);
                    while(!q.empty())
                    {
                        op = q.front(); q.pop();
                        for(k=0;k<8;++k)
                        {
                            tx = tp.x = op.x + dir[k][0];
                            ty = tp.y = op.y + dir[k][1];
                            if(tx<0||tx>=R||ty<0||ty>=C) continue;
                            if(a[tx][ty] == '*') continue;
                            if(vis[tx][ty]==1) continue;
                            vis[tx][ty] = 1;
                            q.push(tp);
                        }
                    }
                }
            }
        }
        pt("%d
",cnt);
    }
    return 0;
}
View Code

   第十二题:1.没有赋初值的变量不要为了图快而使用‘+=’

        2.业务规则理解。

#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#include<iostream>
using namespace std;
#define sc scanf
#define pt printf
#define maxn 105
#define inf 0x3f3f3f3f
int dir[][2]={{0,1},{1,0},{0,2},{2,0},{1,2},{2,1}};
int vis[maxn][maxn][maxn];
typedef struct ob{
    int x[3],dis;
}ob;
int N,M,S;
ob op,tp;
queue<ob> q;
int main()
{
#ifdef WANGNINGLOCAL
    freopen("in.txt", "r", stdin);
    //freopen("out.txt","w",stdout);
#endif
    while(sc("%d%d%d",&S,&N,&M)&&N&&M&&S)
    {
        if(S%2==1)
        {
            pt("NO
"); 
            continue; 
        } 
        int i,j,ans,giv,rec,diff,cei,res,cnt;
        memset(vis,0,sizeof(vis));
        while(!q.empty()) q.pop();
        ans = -1;
        op.x[0] = S; op.x[1] = op.x[2] = 0; op.dis=0;
        
        vis[S][0][0] = 1;
        q.push(op);
        while(!q.empty())
        {
            op = q.front(); q.pop();
            //for(int ii=0;ii<3;++ii) pt("op  %d%c",op.x[ii]," 
"[ii==2]);
            cnt = 0;
            for(i=0;i<3;++i) if(op.x[i]==S/2) ++cnt;
            if(cnt==2) {
                ans = op.dis;
                break;
            }
            tp.dis = op.dis +1 ;
            for(i=0;i<6;++i)
            {
                giv = dir[i][0];
                rec = dir[i][1];
                for(j=0;j<3;++j)
                {
                    if(j==rec||j==giv) continue;
                    res = j;
                }
                tp.x[res] = op.x[res] ;
                if(rec==0)  cei = S;
                else if(rec==1) cei=N;
                else cei = M;
                diff = cei - op.x[rec];
                if(op.x[giv] >= diff){
                    tp.x[rec] = cei;
                    tp.x[giv] = op.x[giv] - diff;
                }
                else{
                    tp.x[rec] = op.x[rec] + op.x[giv];
                    tp.x[giv] = 0;
                }
                if( vis[tp.x[0]][tp.x[1]][tp.x[2]]==0 )
                {
                    vis[tp.x[0]][tp.x[1]][tp.x[2]]=1;
                    //pt("  %d to %d : cei = %d, diff = %d ",giv,rec,cei,diff);
                    //for(int ii=0;ii<3;++ii) pt("  %d%c",tp.x[ii]," 
"[ii==2]);
                    q.push(tp);
                }                
            }
        }
        if(ans!=-1)
        {
           pt("%d
",ans); 
           //for(int ii=0;ii<3;++ii) pt("%d%c",op.x[ii]," 
"[ii==2]);
        } 
        else pt("NO
");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lighten-up-belief/p/10795271.html