UVALIVE 4856 - OmniGravity 【一般小恶心的搜索】

Root :: Regionals 2010 :: Asia - Dhaka

In this problem, we will play with four 2 x 2 squared pieces, an 8 x 8 board, few obstacles and gravity(!!!).

\epsfbox{p4856a.eps}

Initially the board contains few obstacles and the 4 colored pieces randomly placed. An example of an initial configuration is shown in the above diagram. The black squares represent the obstacles and the 4 colored pieces are shown with labels A, B, C and D - (in order to help the colorblind people). Initially there is no gravity and thus the pieces remain at a steady position. We can enable `gravity' in any of the four directions to move the pieces. The pieces move in the direction of gravity. A piece continues to move until it hits an edge of the board, an obstacle or any other piece. The obstacles aren't affected by gravity and so remains in their initial position at all times. We can enable at most one `gravity' at a time. The gravitational direction can only be changed when all the pieces are static.

\epsfbox{p4856b.eps}

The diagram above shows the positions of the pieces after the `gravity' from the right is enabled.

How many different static states can be reached by enabling at least one `gravity'? Two states are different if there is at least once cell that has a different color. A static state is one in which all the pieces are steady!

Input 

The first line of input is an integer T (T$ \le$100) that indicates the number of test cases. Each case consists of 8 lines with 8 characters in each line. Every character will be from the set {ABCD.#}. Dots(.) represent empty spaces, hashes(#) represent obstacles and the alphabets represents the pieces. The frequencies of each letter (A,B,C,D) will be exactly 4 and each letter will occupy positions so that they form squares of size 2 x 2. There is a blank line before every case.

Output 

For each case, output the case number followed by the number of different static states that can be reached from the original position by enabling at least one ``gravity".

Sample Input 

2  
....AA..
....AA#.
...#....
.CCBB...
.CCBB#..
#...##..
.#DD#...
..DD.##.

AABBCCDD
AABBCCDD
........
........
........
........
........
........

Sample Output 

Case 1: 110  
Case 2: 2


这题敲完了真是挺考验代码能力的。本身不是多麻烦的一个题,但是因为“代码自带常挫”,所以由于大常数超时了。
虽然时限是3s,但是看到有人6s过了之后,再看到自己的TLE真是内牛满面啊。
memset是无脑流,大昊说的。诚不我欺啊。以后少用扯淡的memset,果断各种标记数组搞起啊。
因为case数比较小,果断用一个char数组记录当前case是否访问过这个标记。if(vis[hh] != cas)那么就是未访问过咯。
这招秒杀memset啊!!!果断的。O(case * size)=O(100 * 6250000)的memset伤不起啊,一个memset就让我超时了。。。

本题关键词:hash状态BFS、拉链法hash、四方向扫描状态转移、简易重新构图。
拉链法hash通过vis数组大大提高效率,但要注意tot标记要从1开始,因为start数组默认值为0。
把四个块的顶点位置hash成了一个8数位整数,再hash进表里。每次手动解析和重构状态。
方向扫描函数被迫写了四个if语句,果断推荐最坏O(16)的扫描法,常数很小。每次扫描前抠去块所在位置,扫描完毕后重置。
希望将来能学会让方向扫描函数变简短的方法,不过是在不改变我代码风格的前提下,看了看别人的短代码,受不了那种风格。
记得每次是按序扫描,比如向左的话就先从最左的方块开始。这样可以防止后来的方块影响先前的方块。

无用状态很多,其实还可以剪枝,不过代码已经够长了,就这样吧。像这种细节比较多的题目,千万要细心,不然手矬就坑死爹了。

代码:
#include <iostream>
#include 
<cstdio>
#include 
<cstring>
#include 
<queue>
const int hashsize = 6250009;
using namespace std;
#define maxn 10
bool temp[maxn][maxn],map[maxn][maxn];
int state,ans,cas,CAS;
struct hash
{
    
int p,next;
    hash(){}
    hash(
int _p,int _n):p(_p),next(_n){}
}linked[hashsize];
int tot,start[hashsize];//tot should be initialized by 1
char vis[hashsize];
void add(int x)
{
    
int hh = x % hashsize;
    vis[hh] 
= cas;
    linked[tot] 
= hash(x,start[hh]);
    start[hh] 
= tot++;
}
int p[4];
bool v[4];
int S(int num[])
{
    
int sum = 0;
    
for(int i = 0;i < 4;i++)
        sum 
= 100 * sum + num[i];
    
return sum;
}
void QR(int x,int *num)
{
    
for(int i = 3;i >= 0;i--,x/=100)
        num[i] 
= x % 100;
}
inline 
void FULL(char i,char j,bool a)
{
    map[i][j] 
= map[i+1][j]=map[i][j+1]=map[i+1][j+1]=a;
}
bool query(int x)
{
    
int hh = x % hashsize;
    
if(vis[hh] != cas)
        
return false;
    
for(int k = start[hh];k;k = linked[k].next)
        
if(linked[k].p == x)
            
return true;
    
return false;
}
int change(int dir,int state)
{
    
for(int i = 1;i <= 8;i++)
        
for(int j = 1;j <= 8;j++)
            map[i][j] 
= temp[i][j];
    
for(int k = 0;k < 4;k++)
    {
        
int x = p[k] / 10,y = p[k] % 10;
        FULL(x,y,
1);
    }
    
int x,y,mx,my,mark;
    fill(v,v
+4,0);
    
if(dir == 0)//up
    {
        
for(int k = 0;k < 4;k++)
        {
            mark 
= 0,mx = 9;
            
for(int i = 0;i < 4;i++)
                
if(!v[i] && p[i] / 10 < mx)
                {
                    mx 
= p[i] / 10;
                    mark 
= i;
                }
            v[mark] 
= true;
            x 
= p[mark] / 10;
            y 
= p[mark] % 10;
            FULL(x,y,
0);
            
int block = 0;
            
for(int i = x;i >= 1;i--)
                
if(map[i][y] || map[i][y+1])
                {
                    block 
= i;
                    
break;
                }
            x 
= block + 1;
            FULL(x,y,
1);
            p[mark] 
= x * 10 + y;
        }
    }
    
else if(dir == 1)//down
    {
        
for(int k = 0;k < 4;k++)
        {
            mark 
= 0,mx = 0;
            
for(int i = 0;i < 4;i++)
                
if(!v[i] && p[i] / 10 > mx)
                {
                    mx 
= p[i] / 10;
                    mark 
= i;
                }
            v[mark] 
= true;
            x 
= p[mark] / 10;
            y 
= p[mark] % 10;
            FULL(x,y,
0);
            
int block = 8;
            
for(int i = x;i <= 7;i++)
                
if(map[i+1][y] || map[i+1][y+1])
                {
                    block 
= i;
                    
break;
                }
            x 
= block - 1;
            FULL(x,y,
1);
            p[mark] 
= x * 10 + y;
        }
    }
    
else if(dir == 2)//left
    {
        
for(int k = 0;k < 4;k++)
        {
            mark 
= 0,my = 9;
            
for(int i = 0;i < 4;i++)
                
if(!v[i] && p[i] % 10 < my)
                {
                    my 
= p[i] % 10;
                    mark 
= i;
                }
            v[mark] 
= true;
            x 
= p[mark] / 10;
            y 
= p[mark] % 10;
            FULL(x,y,
0);
            
int block = 0;
            
for(int i = y;i >= 1;i--)
                
if(map[x][i] || map[x+1][i])
                {
                    block 
= i;
                    
break;
                }
            y 
= block + 1;
            FULL(x,y,
1);
            p[mark] 
= x * 10 + y;
        }
    }
    
else//right
    {
        
for(int k = 0;k < 4;k++)
        {
            mark 
= 0,my = 0;
            
for(int i = 0;i < 4;i++)
                
if(!v[i] && p[i] % 10 > my)
                {
                    my 
= p[i] % 10;
                    mark 
= i;
                }
            v[mark] 
= true;
            x 
= p[mark] / 10;
            y 
= p[mark] % 10;
            FULL(x,y,
0);
            
int block = 8;
            
for(int i = y;i <= 7;i++)
                
if(map[x][i+1|| map[x+1][i+1])
                {
                    block 
= i;
                    
break;
                }
            y 
= block - 1;
            FULL(x,y,
1);
            p[mark] 
= x * 10 + y;
        }
    }
    
return S(p);
}
void bfs()
{
    queue 
<int> Q;
    state 
= S(p);
    Q.push(state);
    
while(!Q.empty())
    {
        state 
= Q.front();
        Q.pop();
        
for(int i = 0;i < 4;i++)//0~4:up.down.left.right
        {
            QR(state,p);
            
int now = change(i,state);
            
if(!query(now))
            {
                add(now);
                Q.push(now);
                ans
++;
            }
        }
    }
}
void gao()
{
    tot 
= 1;
    fill(p,p 
+ 4,0);
    
for(int i = 1;i <= 8;i++)
    {
        
for(int j = 1;j <= 8;j++)
        {
            
char opt;
            scanf(
" %c",&opt);
            
if(opt == '#')
                temp[i][j] 
= 1;
            
else
            {
                temp[i][j] 
= 0;
                 
if(p[opt-'A'== 0)
                    p[opt
-'A'= i*10+j;
            }
        }
    }
    ans 
= 0;
    bfs();
    printf(
"%d\n",ans);
}
int main()
{
    scanf(
"%d",&CAS);
    
for(cas = 1;cas <= CAS;cas++)
    {
        printf(
"Case %d: ",cas);
        gao();
    }
}

posted on 2011-08-14 15:15 BUPT-[aswmtjdsj] @ Penalty 阅读(304) 评论(0)  编辑 收藏 引用 所属分类: 模拟搜索UVAlive Solution Report


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2011年8月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

导航

统计

常用链接

留言簿(1)

随笔分类(150)

随笔档案(71)

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜