LightOJ 1061 Nクイーンアゲイン(検索+状態圧力DP)

トピック

8 * 8の画像を考えると、その上に8つのクイーンがあり、同じ方向に一度に1つのクイーンしか移動できません。合計8つの方向があります。すべてのクイーンができるように、少なくともいくつのステップが必要かを尋ねてください。お互いを攻撃しませんか?

アイデア

純粋なレイドは機能せず、時間と空間で爆発します。
各クイーンが最後にどこにあるべきかを知っていて、最小ステップ数を計算すると、はるかに簡単になります。ここでは、州の圧力を使用してそれを行うことができます。
最終的な状況は、各行にクイーンが存在するためです。、したがって、各行を記録する必要はありません。クイーンが配置されている列で、この位置に移動するクイーンを列挙します
。dp[sta] [row]は、ソースを考慮したときの状態を意味します。行の行の女王はstaであり、sta&(1 << i)== 1を入力しようとします。つまり、元の画像のi番目の女王は行の行の女王の位置に移動します。ここでの全体的な複雑さは 8 28 ;
次に、すべての法的状況を見つけ、92種類の法的状況を検索します。
最後に、各状況に対して州の圧力をかけ、すべての状況を最小限に抑えます。

题目中有说两个皇后不能同时出现在一个格子里面,在移动过程中会出现相遇的情况;但是通过不同移动的先后顺序是可以避免相遇的情况的;
int p[110][10]; // p[cnt][row] = col;第cnt张图的第row行的Queen在col列
int tp[10]; // tp[row] = col;当前图的row行的Queen在col列
int dp[1 << 9][10]; // dp[sta][row];
int x[10], y[10]; // the position of eight queen;
int cnt;
void dfs(int row) {
    if (row == 8) {
        for (int i = 0;i < 8;++i)
            p[cnt][i] = tp[i];
        ++cnt;
        return ;
    }
    // 枚举第row行的Queen在col列,再判断可行性
    for (int col = 0;col < 8;++col) {
        bool ok = true;
        for (int i = 0;i < row;++i) {
            if (col == tp[i] || tp[i] + i == row + col || tp[i] - i == col - row) {
                ok = false;
                break;
            }
        }
        if (ok){ 
            tp[row] = col;
            dfs(row + 1);
        }
    }
}

int getdis(int cur, int num, int i) {
    //这儿abs很重要
    int t1 = abs(x[i] - num);
    int t2 = abs(y[i] - p[cur][num]);
    int res = 0;
    if (min(t1, t2) != 0) res++;
    if (abs(t1 - t2) != 0) res++;
    return res;
}

int go(int cur, int num, int sta) {
    if (num == 0) return 0;
    if (dp[sta][num] != -1) return dp[sta][num];
    int tans = inf;
    for (int i = 0;i < 8;++i) {
        if (sta & (1 << i)) {
            // 对于第cur张图而言,把第i个Queen放在这张图第(num - 1)行Queen所在的位置
            tans = min(tans, getdis(cur, num - 1, i) + go(cur, num - 1, sta ^ (1 << i)) );
        }
    }
    return dp[sta][num] = tans;
}
int solve() {
    int ans = inf;
    for (int i = 0;i < cnt;++i) {
        memset(dp, -1, sizeof dp);
        ans = min(ans, go(i, 8, (1 << 8) - 1));
    }
    return ans;
}
int main(int argc, const char * argv[])
{    
    dfs(0);
    int kase;cin >> kase;
    while(kase--) {
        int t = 0;
        for (int i = 0;i < 8;++i) {
            char s[10];scanf("%s", s);
            for (int j = 0;j < 8;++j) {
                if (s[j] == 'q') {
                    x[t] = i;
                    y[t] = j;
                    ++t;
                }
            }
        }
        int ans = solve();
        printf("Case %d: %d\n", ++nCase, ans);
    }
    return 0;
}

おすすめ

転載: blog.csdn.net/KIJamesQi/article/details/55519777