Luogu2704POJ1175砲位置

Luogu2704POJ1175砲位置

コマンドN将軍はするつもりM.のグリッドマップ上の自分の大砲を配備します Nは、以下に示すようにN行のM列は、各セルは(「H」で示す)山のマップであってもよいマップからM、それは、普通(「P」で示す)であってもよいです。(山に大砲をデプロイしない)普通地形砲までの各セルに配置することができる。このような黒い領域に示すマップ上の範囲砲攻撃:
Luoguから
同一の地図上の灰色の場合左右横枠に沿って2つずつ、2つのセル上下長手方向に:普通砲兵の展開は、図は、攻撃することができる領域に黒のグリッドを表します。この図は、他の白のグリッドを攻撃していませんでした。マップからの地形の範囲に対する砲撃の目に見える効果。今、将軍は、マップ全体(保証任意の2つの砲兵ユニット間でお互いを攻撃していない、つまり、いずれかの砲兵部隊が攻撃他の砲兵支援の範囲内ではない)不慮の怪我を防止する前提の下で、大砲を展開する方法を計画していました軍の砲兵ユニットの最大数は、エリア内に配置することができます。
N≤100;M≤10。

どのようにそれを行うには?

mが小さいと指摘し、我々は圧力DPを形することができます。

ベースのDP:

\(F [I] [J ] [K] \) を表し\(Iは\)回線状態\(J \)、\ (I-1 \)回線状態\(K \)とき番号放電までを大砲。

転写式:(J、Kの\)は\法的状態にされている、\(J、K、L \)時間を転送することができ、\(F [I] [J] [K] = MAX(F [I] [J ] [K]、F [I -1] [K] [L] +ヴァル[J])\) 説明:転送することができる。この状態で、大砲を傷つけないであろう、すなわち\(J \) \(K = 0 \ )\(J \) \(L = 0 \) 法的地位:大砲の状態は平野にありました。そして、この状態では互いに隣接する大砲を攻撃しません。バイナリマップを圧縮した場合は、山を表して用いることができる\(J \) \(マップ[I] = 0 \)普通にいるか否かを判定する。自身に左右によると、隣接する大砲の攻撃にお互いを取るかどうかを判断します。valが:状態はいくつかの大砲を置くことを示しています。




DPの最適化

我々は発見したオープンdpの配列がする場合は\(1024 * 1024 * 100 \) 宇宙の爆発。それでは、どのようにそれを最適化するには?
私たちは、それが転写時の前処理のすべての法的地位を、法的地位の直接列挙することが可能で、非常に少数の法的地位を発見しました。これは、冗長な状態列挙の数を減らすことができ、この式によって、この時間は十分に問題を抱えています。
我々は見つけることのすべてのFのみからf [i]は、[私は- 1]私たちは、配列の循環、再び宇宙の複雑さを軽減することができ、オーバー移しました。

コードを入れてください

#include <cstdio>
#include <iostream>
#include <ctime>
#define max(x, y) (x > y ? x : y)
#define check(i) (((i & (i << 1)) == 0) && ((i & (i << 2)) == 0) && ((i & (i >> 1)) == 0) && ((i & (i >> 2)) == 0))
#define judge(w, x) (!x & mp[w])
using namespace std;
const int INF = 1 << 29;
const int MAXN = 101;
const int MAXM = 11;
int n, m;
int mp[MAXN];
//数组要开够大!!!不然越界会修改不该修改的
int S[100], CS[100], cnt;
int f[3][100][100];
inline int count(int x)
{ 
    int res = 0;
    for (; x; x -= x & -x)
        ++res;
    return res;
}
inline void test(const int x)
{
    for (register int i = 10; i >= 0; --i)
        cerr << ((x >> i) & 1);
    cerr << endl;
}
int main()
{
#ifdef lky233
    freopen("testdata.in", "r", stdin);
    freopen("testdata.out", "w", stdout);
#endif
    scanf("%d %d", &n, &m);
    for (register int i = 1; i <= n; ++i)
    {
        //读入地图并进行状压
        register int res = 0;
        for (register int j = 0; j < m; ++j)
        {
            char c = 0;
            while ((c = getchar()) != 'H' && c != 'P')
                ;
            res |= ((c == 'H' ? 1 : 0) << j);
        }
        mp[i] = res;
    }
    //预处理可行状态
    for (register int i = 0; i < (1 << m); ++i)
        //判断相邻的炮兵是否会攻击到
        if (((i & (i << 1)) == 0) && ((i & (i << 2)) == 0) && ((i & (i >> 1)) == 0) && ((i & (i >> 2)) == 0))
        {
            cnt++;
            S[cnt] = i;
            CS[cnt] = count(i);
        }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= cnt; j++)
            if ((mp[i] & S[j]) == 0)//炮兵均在平原
                for (int t = 1; t <= cnt; t++)
                    if ((S[t] & S[j]) == 0)//可以转移
                        for (int z = 1; z <= cnt; z++)
                            if (((S[t] & S[z]) == 0) && ((S[z] & S[j]) == 0))//可以转移
                                f[i & 1][t][j] = max(f[i & 1][t][j], f[(i - 1) & 1][z][t] + CS[j]);
    int ans = 0;
    for (register int i = 1; i <= cnt; ++i)
        for (register int j = 1; j <= cnt; ++j)
            ans = max(ans, f[n & 1][i][j]);
    cout << ans << endl;
    cerr << clock() << "ms" << endl;
}

本篇题解到此结束
ありがとうございます。

おすすめ

転載: www.cnblogs.com/Shiina-Rikka/p/11590230.html