Gym - 100971A-DFS-值得思考-两种思路

http://codeforces.com/gym/100971/problem/A
比赛中第一眼就看到这个了,当时以为是简单的搜索就完事了,后来发现还得枚举情况,就想了三种特判的条件,分别把模糊的地方当做陆地和海洋处理,如果都是1 那么就是ambiguous。
如果都大于1或者都等于0 肯定是不可以的。impossible.
其他情况哪个等于1 就置换哪个。
思路是没错的。
错误在搜索的地方,我开始在搜索判断小岛数量,只判断.的情况,因为’.’是合法的陆地。但是这样当两个问号相连时就出错了。比如
“####”
“.??.”
“####”
“####”
” 就会出现 impossible。
但其实是可以的。。所以搜索时把?号也给搜索了就好了。
ps:开始以为是壮压来着,因为m,n都是很小的数字。。
并且每个??号都有可能是?和#.所以要枚举好多种情况哦
错就错在不用枚举情况的,为什么呢,如果把他们都成#,那么显然是错的。,那为什么当做.会是对的呢。
因为 都当成 . ,如果是出现两个岛屿的情况,会被条件pass。
而在一个岛屿内,你如果不是当前要判断的那个地方,你当成.和#和当前好想没啥关系啊。。

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int maxn=200;
char  a[maxn][maxn];
char b[maxn][maxn];
int m,n;
int fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int dfs1(int a1,int b1)
{   if(a1>m||a1<1||b1>n||b1<1) return 0;
      if(b[a1][b1]=='#') return 0;
      b[a1][b1]='#';
      for(int i=0;i<4;i++)
      {   int xx=a1+fx[i][0];
           int yy=b1+fx[i][1];
           if(b[xx][yy]=='.') dfs1(xx,yy);
      }
   return 0;
}
int dfs()
{   int sum=0;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
          b[i][j]=a[i][j];
    for(int i=1;i<=m;i++)
     for(int j=1;j<=n;j++)
          if(b[i][j]=='.')
     {   sum++;
         dfs1(i,j);
         }
    return sum;
}
int main()
{
      cin>>m>>n;
      for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
          cin>>a[i][j];
          bool flag=false;
          bool qq=false;
          bool ss=false;
        for(int i=1;i<=m;i++)
            {for(int j=1;j<=n;j++)
        {   if(a[i][j]=='?')
             {a[i][j]='.';
             int sum1=dfs();
             a[i][j]='#';
              int sum2=dfs();
              if(sum1==1&&sum2==1){flag=true;break;}
              else if(sum1>1&&sum2>1) {qq=true;break;}
              else  if(sum1==0&&sum2==0) {ss=true;break;}
                else
                {
                   if(sum1==1) a[i][j]='.';
                   else a[i][j]='#';
              }
             }
        }
        if(flag||qq||ss) break;
        }
   if(flag)
       puts("Ambiguous");
        else if(qq)
            puts("Impossible");
            else if(ss)
                puts("Impossible");
        else
        {  for(int i=1;i<=m;i++)
           {for(int j=1;j<=n;j++)
               printf("%c",a[i][j]);
                printf("\n");

           }

        }



    return 0;
}

‘看了别人的代码,比我的更好理解。。
他是通过判断数量来推断的。
不成立的条件就是存在两个.. 可以直接除去
存在ambigous的情况是当一个地方的改变不影响连通度(只改变一个当然正常,若是改变很多就是说明这个点是桥。是不能改变的。)
其他情况就正常输出。
这道题和我卡的数据都不一样,错误在于判断相等后(相等就是说这个问号没在大陆里),可以直接跳出的
没有.的话,

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
/*看了别人的代码,和我判断的方式不一样,
他是通过判断陆地的大小,来区分的。
我感觉我写得好,
因为我不太擅长计数相关。
*/
const int maxn=200;
int fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
bool vis[maxn][maxn];
int all;
int m,n;
int b[maxn][maxn];
char a[maxn][maxn];
int sum;
int dfs(int a1,int b1)
{    if(a1<1||a1>m||b1>n||b1<1)
       return 0;
      sum++;
    vis[a1][b1]=true;
    for(int i=0;i<4;i++)
    {  int xx=a1+fx[i][0];
       int yy=b1+fx[i][1];
        if(!vis[xx][yy]&&b[xx][yy])
        dfs(xx,yy);
    }
    return 0;
}
int main()
{   int k1,k2;
     memset(vis,false,sizeof(vis));
     cin>>m>>n;
     for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
         {cin>>a[i][j];
         if(a[i][j]=='.') {b[i][j]=1;k1=i;k2=j;}
         else if(a[i][j]=='?') b[i][j]=2;
         }

         int s=0;
         memset(vis,false,sizeof(vis));
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
        {   if(b[i][j]==1&&!vis[i][j])
             {sum=0;
             dfs(i,j);
             s++;}
        }
        bool flag=false;
        if(s>1)
        {  puts("Impossible");return 0;
        }
       else
       {  int all=sum;
           for(int i=1;i<=m&&!flag;i++)
             for(int j=1;j<=n&&!flag;j++)
           {  if(b[i][j]==2)
               {b[i][j]=0;
               sum=0;
               memset(vis,false,sizeof(vis));
               dfs(k1,k2);
               //cout<<sum<<endl;
               if(sum==all)  continue;
               if(sum==all-1){flag=true;break;}
               else b[i][j]=1;}
           }
       }
   if(flag)
     puts("Ambiguous");
   else
   {   for(int i=1;i<=m;i++)
        {for(int j=1;j<=n;j++)
        {  if(b[i][j])
             cout<<'.';
             else if(b[i][j]==0)
                cout<<'#';


        }
        cout<<endl;

        }
   }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值