1. 程式人生 > >Pocket Cube (模擬+DFS)

Pocket Cube (模擬+DFS)

題目連結

題意:給一個n,按下圖順序輸入,求n次操作能轉出最多多少個面.

題解:dfs模擬即可,不過需要剪枝,不然爆炸~//二階魔方模板,三階同理

程式碼如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
#define lson id<<1
#define rson id<<1|1
const int maxn = 10;
const int inf = 0x3f3f3f3f;
//二階魔方
int mp[30], s[10][30], n;//mp[]為中間變數,s[x][]儲存的是dfs第x層的mp[]
int turn[6][30] = {
    { 0,2,6,12,16,18,20,22,4,5,11,10 },//0~7為轉的那一圈,8~11為與之相對的側面的一面也要轉同向(請摺紙做!!!)
    { 1,3,7,13,17,19,21,23,9,8,14,15 },
    { 1,0,4,10,18,19,15,9,23,22,20,21 },
    { 3,2,5,11,16,17,14,8,7,6,12,13 },
    { 4,5,6,7,8,9,23,22,0,2,3,1 },
    { 10,11,12,13,14,15,21,20,16,17,19,18 }
};
//剪枝三:同一flag操作>=3就沒有意義了
int cnt[10][10];//用於記錄第x層的flag操作次數
int z_cnt[10];//同mp與s的關係

int cas = 1;//用於輸出所有中間結果的
void debug() 
{
    cout << endl;
    cout << "Case " << cas++ << endl;
    cout << "    " << mp[0] << " " << mp[1] << endl;
    cout << "    " << mp[2] << " " << mp[3] << endl;
    for (int i = 4; i <= 9; i++)
        cout << mp[i] << " ";
    cout << endl;
    for (int i = 10; i <= 15; i++)
        cout << mp[i] << " ";
    cout << endl;
    cout << "    " << mp[16] << " " << mp[17] << endl;
    cout << "    " << mp[18] << " " << mp[19] << endl;
    cout << "    " << mp[20] << " " << mp[21] << endl;
    cout << "    " << mp[22] << " " << mp[23] << endl;
}

int check() 
{
    int cnt = 0;
    int t = mp[0];
    if (t == mp[1] && t == mp[2] && t == mp[3])cnt++;
    t = mp[4];
    if (t == mp[5] && t == mp[10] && t == mp[11])cnt++;
    t = mp[6];
    if (t == mp[7] && t == mp[12] && t == mp[13])cnt++;
    t = mp[8];
    if (t == mp[9] && t == mp[14] && t == mp[15])cnt++;
    t = mp[16];
    if (t == mp[17] && t == mp[18] && t == mp[19])cnt++;
    t = mp[20];
    if (t == mp[21] && t == mp[22] && t == mp[23])cnt++;
    //debug();
    //cout << "cnt== " << cnt << endl;
    return cnt;
}
void turning(int flag)
{
    int x, y, z;
    x = mp[turn[flag][0]], y = mp[turn[flag][1]];
    for (int i = 0; i < 6; i++)
        mp[turn[flag][i]] = mp[turn[flag][i + 2]];
    mp[turn[flag][6]] = x, mp[turn[flag][7]] = y;
    z = mp[turn[flag][8]];
    for (int i = 8; i < 11; i++)
        mp[turn[flag][i]] = mp[turn[flag][i + 1]];
    mp[turn[flag][11]] = z;
}
void init(int x)//x為層數  
{
    for (int i = 0; i < 25; i++)
        mp[i] = s[x][i];
    for (int i = 0; i < 6; i++)
        z_cnt[i] = cnt[x][i];
}
int dfs(int flag, int x)  //flag為轉的型別,x為層數
{
    turning(flag);
    int y = check();
    if (x == n)
        return y;
    if (y == 6)  return y;  //剪枝二:當有一組出現6時可以結束了

    //先將當前層的mp存下來
    for (int i = 0; i < 25; i++)     
        s[x][i] = mp[i];
    for (int i = 0; i < 6; i++)
        cnt[x][i] = z_cnt[i];
    x++;
    for (int i = 0; i < 6; i++)
    {
        int j = flag ^ i;
        if ((flag^i) == 1) continue;//剪枝一:左上一次,右上一次就復原了,剪調
        z_cnt[i]++;
        if (z_cnt[i] >= 3) continue;//剪枝三
        init(x - 1);
        y = max(y, dfs(i, x));
    }
    return y;
}
void solve()
{
    init(0);
    memset(cnt, 0, sizeof(cnt));
    int ans = check();
    for (int i = 0; i < 6; i++)
    {
        init(0);
        z_cnt[i]++;
        ans = max(ans, dfs(i, 1));
    }
    cout << ans << endl;
}
void read()
{
    for (int i = 0; i < 24; i++)        
        scanf("%d", &s[0][i]);
}
int main()
{
    while (~scanf("%d", &n))
    {
        read();
        solve();
    }
    return 0;
}