hdu3220Alice’s Cube(IDA*)

題目請戳這裏

題目大意:給一個超級立方體(具體看題目中的圖),16個點,每個點有4個相鄰點,圖中有標識。現在每個點安一個燈泡。一共16個燈泡,有8盞亮8盞滅,現在可以交換任意相鄰的2盞狀態不同的燈的狀態。求最少多少步能使編號1-8的8個燈泡亮,其他的滅。

題目分析:題目要求3步以內就夠了。16個點,每個點有4個相鄰點,16^4,不過case有13000+個。

可以考慮IDA*。將16個燈泡壓縮成一個整數,根據圖可以將每個點的相鄰點保存下來。直接搜就可以了。

啓發函數很顯然,就是高8位1的個數,因爲要保證高8位所有的數爲0,只要高8位有一個1,那麼至少要一步才能將其交換,所以高8位有多少1就至少要多少步。

其實不要這個啓發函數其實也是可以過的。

不過寫的時候卡在了按位與操作上了。。。還是狀態壓縮寫少了。。。

詳情請見代碼:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100000;

bool flag[N];
bool ok;
int ans;
int adj[16][4] =
{
    {1,2,4,8},
    {0,3,5,9},
    {0,3,6,10},
    {1,2,7,11},
    {0,5,6,12},
    {1,4,7,13},
    {2,4,7,14},
    {3,5,6,15},
    {0,9,10,12},
    {1,8,11,13},
    {2,8,11,14},
    {3,9,10,15},
    {4,8,13,14},
    {5,9,12,15},
    {6,10,12,15},
    {7,11,13,14},
};
int A(int x)
{
    int i;
    int ret = 0;
    for(i = 15;i >= 8;i --)
    {
        ret += (bool)(x&(1<<i));
    }
    return ret;
}
void dfs(int cur,int dp)
{
    if(cur == 255)
    {
        ok = true;
        return;
    }
    if(ok)
        return;
    if(dp + A(cur) > ans)
        return;
    int i,j,k;
    for(i = 15;i >= 0;i --)
    {
        if(cur&(1<<i))
        {
            for(j = 0;j < 4;j ++)
            {
                int tmp = 15 - adj[15-i][j];
                if(((cur>>tmp)&1)^((cur>>i)&1))//!!!!!
                {
                    int tp = cur;
                    tp ^= (1<<i);
                    tp ^= (1<<tmp);
                    if(flag[tp] == false)
                    {
                        flag[tp] = true;
                        dfs(tp,dp + 1);
                        flag[tp]= false;
                    }
                }
            }
        }
    }
}
int main()
{
    int t,i,cas = 0;
    scanf("%d",&t);
    int a[20];
    while(t --)
    {
        printf("Case #%d: ",++cas);
        for(i = 0;i < 16;i ++)
            scanf("%d",a + i);
        int tmp = 0;
        for(i = 0;i < 8;i ++)
            tmp += a[i];
        if(tmp > 3)
        {
            printf("more\n");
            continue;
        }
        tmp = 0;
        for(i = 15;i >= 0;i --)
        {
            if(a[i])
                tmp |= (1<<(15 - i));
        }
        ans = -1;
        while(1)
        {
            ans ++;
            ok = false;
            flag[tmp] = true;
            dfs(tmp,0);
            flag[tmp] = false;
            if(ok)
                break;
            if(ans >= 3)
            {
                ans ++;break;
            }

        }
        if(ans > 3)
            puts("more");
        else
            printf("%d\n",ans);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章