zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    VS2010中使用JSONCPP方法
    VC获取外网IP
    JSON样例
    JSON详解
    vc获取本地IP
    Java中创建对称密钥的代码
    密和解密程序的一些概念
    在ireport报错 报 jdk5找不到的解决办法
    Java中创建对称密钥的步骤
    比较好用的一个jaspereport模板 生成html页面模板
  • 原文地址:https://www.cnblogs.com/lighten-up-belief/p/10795271.html
Copyright © 2011-2022 走看看