poj_1288_回溯

题目描述:  

   就是给一系列frame(字母构成的矩形边框,一个frame为一个大写字母组成的边框)。然后给一张图(矩形阵列),该图是fame按照某个次序往上覆盖的结果显示。

 

解题思路:

   回溯。注意的地方比较多,首先是结果图的存储问题,需要记录争取的字母框四条边位置;其次是回溯的思路,从顶层开始找符合条件的frame,直到最底层;最后是字典序输出问题,这个题理论上26个字母最大结果是不够存的,不过这个题的测试数据似乎开1000也就可以了。

   几个小错误地方:(1)字符串清空(2)多组输入!  

 

代码:

#include <stdio.h>
#include <stdlib.h>
#define N 31
#define MAX 1000

typedef struct
{
   int left,right,top,bottom;
   char c;
}LETTER;

LETTER l[27], letter[27];
int f[N],flag[27],count,r,h,w,result[27],g;
char str[N][N],s[MAX][27];

int testFrame(int t)
{
   int i,j;
   int tt=letter[t].top,b=letter[t].bottom,l=letter[t].left,r=letter[t].right;

   i=tt;
   for(j=l;j<=r;j++)                 
     if((flag[str[i][j]-'A'] == 0) && (str[i][j] != letter[t].c))
        return 0;
   i=b;
   for(j=l;j<=r;j++)                 
     if((flag[str[i][j]-'A'] == 0) && (str[i][j] != letter[t].c))
        return 0;
   j=l;
   for(i=tt+1;i<b;i++)
     if((flag[str[i][j]-'A'] == 0) && (str[i][j] != letter[t].c))
        return 0;
   j=r;
   for(i=tt+1;i<b;i++)
     if((flag[str[i][j]-'A'] == 0) && (str[i][j] != letter[t].c))
        return 0;
    return 1;
}

void try(int num)
{
   int i;
   if(num>count)
   {
      for(i=count;i>=1;i--)
         s[g][count-i] = letter[result[i]].c;
      g++;
   }
   else
   {
      for(i=count;i>=1;i--)//从顶层开始找
      
         if((0 == flag[letter[i].c-'A'])&&( testFrame(i) == 1))//该点未被检查过且是一个frame
         {
            flag[letter[i].c-'A'] = 1;
            result[r] = i;
            r++;
            try(num+1);
            r--;
            flag[letter[i].c-'A'] = 0;      
         }
      }
   }
}
int cmp ( const void *a , const void *b )
{
    return strcmp((char *)a ,(char *)b);
}

main()
{
   int i,j;
  
   while(scanf("%d %d",&h,&w)!=EOF)
   {
       //input
       for(i=0;i<h;i++)
          scanf("%s",str[i]);
       //遍历
       for(i=0;i<26;i++)
          f[i] = 0;
      
       for(i=0;i<h;i++)
          for(j=0;j<w;j++)
          {
             if(str[i][j] >='A' && str[i][j]<='Z')
             {
                if(f[str[i][j]-'A']==0) //未记录过
                {
                   l[str[i][j]-'A'].c = str[i][j];
                   l[str[i][j]-'A'].left = j;
                   l[str[i][j]-'A'].right = j;
                   l[str[i][j]-'A'].top = i;
                   l[str[i][j]-'A'].bottom = i;
                   f[str[i][j]-'A'] = 1;
                }
                else
                {
                   if( j < l[str[i][j]-'A'].left)
                      l[str[i][j]-'A'].left = j;
                   if( j > l[str[i][j]-'A'].right)
                      l[str[i][j]-'A'].right = j;
                   if( i > l[str[i][j]-'A'].bottom)
                      l[str[i][j]-'A'].bottom = i;
                }
             }
          }
       count = 0;
       //数一共几个。并按次序记录。
       for(i=0;i<26;i++)
          if(f[i]!=0)
          {
              count ++;
              letter[count] = l[i];//复制到letter里。按次序,前count个。
          }
       for(i=0;i<26;i++)
             flag[i] = 0;
       r=1;
       memset(s,0,sizeof(s));
       g=0;
       try(1);
       qsort(s,g,sizeof(s[0]),cmp);//排序s[],一共g个(0->g-1)
       for(i=0;i<g;i++)
          printf("%s\n",s[i]);
  
   //system("pause");
   return 0;
  
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值