讨论 / 这是我从INTERNET上找到的……
飞雪天涯 2010-07-26 07:14:00
点我顶贴 收藏 删除
炮兵阵地

Time Limit: 2000MS Memory Limit: 65536K

Total Submissions: 3160 Accepted: 950

Description

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。

现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

Input

第一行包含两个由空格分割开的正整数,分别表示N和M;

接下来的N行,每一行含有连续的M个字符(’P’或者’H’),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

Output

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

Sample Input

5 4

PHPP

PPHH

PPPP

PHPP

PHHP

Sample Output

6

经典的状态压缩DP,黑书原题,基本做法我就不多说了,反正是保存两行的状态去推第三行。

PKU上做过好多类似的题目,Mondriaan’s Dream就是其中最经典的。

然而本题直接用相似方法去搞,然后就直接TLE了。

于是开始了我漫长的代码优化过程。

首先是先用DFS把所有可行的状态转移存起来,结果MLE了。

后来发现有些状态还是无用的,于是先用DFS枚举所有可行状态,再DFS所有可行转移。

然后觉得还会TLE,于是又把可行状态转移按最后一行分类,这样可以直接在最后一行上减很多枝。

就这样写了,还是1.7s才过,实在想不到怎么样才能再优化了,或者是我的代码太次?

贴在这里了,大牛们帮我挑挑刺吧!

#include <stdio.h>

#include <memory.h>

#include <vector>

using namespace std;

int n,m;

int sts[102],ps[1<<10],pn;

char grids[102][12];

struct elem

{

int la,lb,tot;

elem(const int &aa=0,const int &bb=0,const int &tt=0):la(aa),lb(bb),tot(tt){}

};

int dps[2][1<<10][1<<10];

void input()

{

scanf("%d %d",&n,&m);

int i,j;

for (i=0;i<n;++i)

scanf("%s",grids[i]);

for (i=0;i<n;++i)

{

sts[i]=0;

for (j=0;j<m;++j)

if (grids[i][j]==’H’)

sts[i]|=(1<<j);

}

}

vector<elem> chs[1<<10];

void dfs(const int &curr,const int &la,const int &lb,const int &dep,const int &tot)

{

if (dep==m)

{

chs[curr].push_back(elem(la,lb,tot));

return;

}

dfs(curr,la,lb,dep+1,tot);

if (la&(1<<dep)) return;

if (lb&(1<<dep)) return;

if (dep>0&&(curr&(1<<(dep-1)))) return;

if (dep>1&&(curr&(1<<(dep-2)))) return;

dfs(curr|(1<<dep),la,lb,dep+1,tot+1);

}

void pdfs(const int &curr,const int &dep)

{

if (dep==m)

{

ps[pn++]=curr;

return;

}

pdfs(curr,dep+1);

if (dep>0&&(curr&(1<<(dep-1)))) return;

if (dep>1&&(curr&(1<<(dep-2)))) return;

pdfs(curr|(1<<dep),dep+1);

}

void init()

{

int t=(1<<m),i,j;

for (i=0;i<t;++i)

chs[i].clear();

pn=0;

pdfs(0,0);

for (i=0;i<pn;++i)

for (j=0;j<pn;++j)

dfs(0,ps[i],ps[j],0,0);

}

int dp()

{

memset(dps,-1,sizeof(dps));

dps[1][0][0]=0;

int t=(1<<m),i,j,k,curr,la,lb;

for (i=0;i<n;++i)

{

memset(dps[i&1],-1,sizeof(dps[i&1]));

for (j=0;j<pn;++j)

if (!(sts[i]&ps[j]))

{

for (k=0;k<chs[ps[j]].size();++k)

if (dps[1-(i&1)][chs[ps[j]][k].la][chs[ps[j]][k].lb]>-1&&dps[i&1][ps[j]][chs[ps[j]][k].la]<dps[1-(i&1)][chs[ps[j]][k].la][chs[ps[j]][k].lb]+chs[ps[j]][k].tot)

dps[i&1][ps[j]][chs[ps[j]][k].la]=dps[1-(i&1)][chs[ps[j]][k].la][chs[ps[j]][k].lb]+chs[ps[j]][k].tot;

}

}

int ans=0;

for (i=0;i<pn;++i)

for (j=0;j<pn;++j)

if (ans<dps[1-(n&1)][ps[i]][ps[j]])

ans=dps[1-(n&1)][ps[i]][ps[j]];

return ans;

}

int main()

{

input();

init();

printf("%d\n",dp());

return 0;

}

#1 飞雪天涯@2008-11-14 00:20:00
回复 删除
顶!
#2 Hakkinen@2010-07-26 07:14:00
回复 删除
居然用 <vector> ,这个好像更慢 :)

你是不是用4进制的?我实测后发现3进制直接算比4进制位运算要快一点,不过我两个都可以在PKU上AC :)

查看更多回复
提交回复