HDU5838 G.Mountain(容斥+dfs+状压)

链接

n n n m m m范围很小,考虑状压

但是因为谷底的存在不方便状压

所以我们定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为从小到大填了 i i i个数,谷底填过的状态是 j j j

这样当我们需要把数字 i + 1 i+1 i+1填上去的话

Ⅰ . 可 以 填 充 在 一 个 没 有 被 填 过 的 谷 底 Ⅰ.可以填充在一个没有被填过的谷底 .

Ⅱ . 可 以 填 充 在 一 个 没 有 被 填 过 的 非 谷 底 Ⅱ.可以填充在一个没有被填过的非谷底 .

但 仔 细 想 象 , 满 足 转 移 Ⅱ 的 非 谷 底 需 要 有 一 些 限 制 但仔细想象,满足转移Ⅱ的非谷底需要有一些限制 ,

就 是 周 围 不 能 含 有 未 被 填 数 的 谷 底 , 否 则 后 续 填 的 数 比 现 在 大 , 不 符 合 谷 底 要 求 就是周围不能含有未被填数的谷底,否则后续填的数比现在大,不符合谷底要求 ,,

然后转移就可以暴力枚举当前谷底的状态填数就好了,每个状态的信息可以预处理

但是这样就完了吗?native…这样有不合法的状态算进去了

比如某个非谷底,本来不能比周围海拔都低(不然就变成谷底了)

但上诉算法还是照常算进去了!!!

仔细想想,若一个非谷底的周围没有谷底,那么状压过程中可能会比周围海拔都低

比如 x x x位置是谷底位置, y y y z z z是非谷底位置(但状压肯可能会计算为谷底)

那 么 计 算 x 时 , 成 为 谷 底 组 合 方 案 是 : x , x y , x z , x y z 那么计算x时,成为谷底组合方案是:x,xy,xz,xyz x,:x,xy,xz,xyz

但我们只需要 x x x而已,其他非谷底是不能变成谷底的!!!

所以我们再计算 x y xy xy,成为谷底组合方案是 f ( x y ) : x y , x y z f(xy):xy,xyz f(xy):xy,xyz

所以我们在计算 x z xz xz,成为谷底组合方案是 f ( x z ) : x z , x y z f(xz):xz,xyz f(xz):xz,xyz

所以我们再计算 x y z xyz xyz,成为谷底组合方案是 f ( x y z ) : x y z f(xyz):xyz f(xyz):xyz

那 么 只 有 x 的 方 案 经 过 容 斥 就 是 x = f ( x ) − f ( x y ) − f ( x z ) + f ( x y z ) 那么只有x的方案经过容斥就是x=f(x)-f(xy)-f(xz)+f(xyz) xx=f(x)f(xy)f(xz)+f(xyz)

这 个 容 斥 的 过 程 对 应 代 码 里 的 d f s 这个容斥的过程对应代码里的dfs dfs

#include 
using namespace std;
typedef long long ll;
#define int long long
const int maxn=1e5+10;
const int mod=772002;
char st[10][10],a[10][10];
int n,m,pos[1500],x[10],y[10],mou[1500];
ll ans,dp[30][1080]; 
int dx[10]={0,0,1,1,1,-1,-1,-1};
int dy[10]={1,-1,0,1,-1,0,1,-1};
ll DP(int num)
{
	int id=0;
	for(int i=0;i=0&&ny>=0&&nx=n||ny<0||ny>=m )	continue;
		if( a[nx][ny]=='X' )	flag=1;//周围有谷底,那么自己不可能成为谷底 
	}
	if( !flag&&a[x][y]!='X' )//有可能成为谷底
	{
		a[x][y]='X';
		dfs(step+1,num+1);
		a[x][y]='.';
	}
	dfs(step+1,num);
}
bool check()
{
	for(int i=0;i=0&&nx=0&&ny

你可能感兴趣的:(icpc,dp真题)