Chinaunix首页 | 论坛 | 博客
  • 博客访问: 182194
  • 博文数量: 48
  • 博客积分: 4060
  • 博客等级: 上校
  • 技术积分: 1080
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-23 23:24
文章分类

全部博文(48)

文章存档

2011年(1)

2010年(8)

2009年(2)

2008年(37)

我的朋友

分类: C/C++

2008-04-23 09:42:21

题目意思:给你一个局面的strange billboard,通过最少次的反转,问能否把它全部变成白色
其实这个题目和反转拼图一样,不过yzfy上数据更强,我还没能过。
解题思路:通过对第一行的状态进行枚举,枚举我用的是recur()递归做的,一旦第一行的状态确定了,下面各行的状态也就确定了。在这个过程中有几个优化地方,开始没优化在hdu上超时了。
第一个优化:如果你要反转的次数已经超过了an记录的结果,就可以不用继续下去if(t>=an) return;
第二个优化:我是枚举第一行,如果列比行大号多,就可以把矩阵转一下,这样可以减少好多时间
比如4*16这样枚举要2^16 如果变成16*4这样枚举就只要2^4
缺点:这个程序耗时也还是比较多,500多ms 可以通过转化为位运算进一步优化,暂时还没想出来!
#include
int m,n,D[20][20],tt[20][20];
int an;
inline void copy(int a[][20],int b[][20])
{
  int i,j;
    for(i=1;i<=m;i++)
    {
      for(j=1;j<=n;j++)
        a[i][j]=b[i][j];
    }
}
inline void flip(int D[][20],int x,int y)
{
  D[x][y]^=1;
  if(x>1) D[x-1][y]^=1;
  if(x  if(y>1) D[x][y-1]^=1;
  if(y}
void display()
{
  int i,j;
    for(i=1;i<=m;i++)
    {
      for(j=1;j<=n;j++)
        printf("%d ",D[i][j]);
      printf("\n");
    }
printf("\n");
}
void recur(int p,int t)
{
  int i,j,k,totel,f;
  if(t>=an) return;
  if(p>n)
  {
 //printf("t=%d\n",t);
    //display();
    copy(tt,D);
    totel=t;
    for(k=2;k<=m;k++)
    {
      for(j=1;j<=n;j++)
        if(tt[k-1][j]==1)
        {
        flip(tt,k,j);totel++;
        if(totel>=an) goto loop;
        }
    }
    f=1;
    //display();
    //printf("over\n\n");
    for(j=1;j<=n;j++)
      if(tt[m][j]==1){f=0;break;}
    if(f&&totel      an=totel;
      //printf("over\n\n");
loop:    return;
  }
  for(i=0;i<=1;i++)
  {
    if(i==1)
    {
    flip(D,1,p);
    recur(p+1,t+1);
    flip(D,1,p);
    }
    else
    {
    recur(p+1,t);
    }
    //if(i==1)flip(D,1,p);
  }
}
int main()
{
  int i,j,flag,temp;
  char ch[20];
  while(scanf("%d%d",&m,&n)&&m+n)
  {
    flag=0;
    for(i=1;i<=m;i++)
    {
    scanf("%s",ch);
    for(j=1;j<=n;j++)
      if(ch[j-1]=='X'){D[i][j]=1;flag=1;}
      else D[i][j]=0;
    }/*
    for(i=1;i<=m;i++)
    {
      for(j=1;j<=n;j++)
        printf("%d ",D[i][j]);
      printf("\n");
    }*/
    //display();
    ///原来就是这里没有换过来 导致超时
    if(n>m)
    {
      for(i=1;i<=m;i++)
      for(j=i+1;j<=n;j++)
      {
        temp=D[i][j];D[i][j]=D[j][i];D[j][i]=temp;                
      }
      temp=m;m=n;n=temp;     
    }
    if(flag==0)
    {printf("You have to tap 0 tiles.\n");continue;}
    an=1005;
    recur(1,0);
    if(an==1005)
      printf("Damaged billboard.\n");
    else
    printf("You have to tap %d tiles.\n",an);
  }
}
 
阅读(867) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~