POJ 3133

第一次了解插头DP,后来一点点索引到了CDQ大佬那篇08年度集训队论文,只是看了一点点开头,思路确实很精妙,orz。然而开始还并没领会,参考了部分别的犇的代码,才有了整体框架思路,关于进制和哈希方法的套路才得以窥知一二。

进位制采用\(2^n\)进制,即使冗余,但这从计算机角度思考才是最优的.

这篇题解写的太粗略了,留个坑补下吧

#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const int N= 12;
const int inc= 2;
const int HASH= 1e5+7;
const int STATE= 1e6+10;

int bd[N][N], dp[2][1<<(N<<1)];
int code[N];
int n, m;

struct HashMap
{
	int head[HASH];
	int next[STATE], state[STATE], dp[STATE];
	int sizes;
	void init()
	{
		sizes= 0;
		memset(head, -1, sizeof(head));
	}
	void push(int st, int ans)
	{
		int h= st%HASH;
		for (int i= head[h]; -1!= i; i= next[i]){
			if (st== state[i]){
				if (ans< dp[i]){
					dp[i]= ans;
				}
				return;
			}
		}
		dp[sizes]= ans;
		state[sizes]= st;
		next[sizes]= head[h];
		head[h]= sizes++;
	}
}hm[2];
// quad
void Decode(int code[], int m, LL st)
{
	for (int i= 0; i<= m; ++i){
		code[i]= st&3;
		st>>= inc;
	}
}
int Encode(int code[], int m)
{
	int st= 0;
	for (int i= m; i>= 0; --i){
		st<<= inc;
		st|= code[i];
	}

	return st;
}
void LShift(int code[], int m)
{
	for (int i= m; i> 0; --i){
		code[i]= code[i-1];
	}
	code[0]= 0;
}
void DpBlank(int cur, int i, int j)
{
	int lf, up;
	for (int k= 0; k< hm[cur].sizes; ++k){
		Decode(code, m, hm[cur].state[k]);
		lf= code[j-1];
		up= code[j];

		if (lf || up){
			if (lf && up){
				if (lf!= up){
					continue;
				}
				else{
					code[j-1]= code[j]= 0;
					if (j== m){
						LShift(code, m);
					}
					hm[cur^1].push(Encode(code, m), hm[cur].dp[k]+1);
				}
			}
			else{
				int pre= lf ? lf : up;
				if (j< m){	// ->
					code[j-1]= 0;
					code[j]= pre;
					hm[cur^1].push(Encode(code, m), hm[cur].dp[k]+1);
				}
				if (i< n){	//down
					code[j-1]= pre;
					code[j]= 0;
					if (j== m){
						LShift(code, m);
					}
					hm[cur^1].push(Encode(code, m), hm[cur].dp[k]+1);
				}
			}
		}
		else{
			code[j-1]= code[j]= 0;	// do nothing
			if (j== m){
				LShift(code, m);
			}
			hm[cur^1].push(Encode(code, m), hm[cur].dp[k]);

			if (i< n && j< m){
				code[j-1]= code[j]= 2;
				hm[cur^1].push(Encode(code, m), hm[cur].dp[k]+1);

				code[j-1] =code[j]= 3;
				hm[cur^1].push(Encode(code, m), hm[cur].dp[k]+1);
			}
		}
	}
}
void DpBlock(int cur, int i, int j)
{
	for (int k= 0; k< hm[cur].sizes; ++k){
		Decode(code, m, hm[cur].state[k]);
		if (code[j-1] || code[j]){
			continue;
		}
		code[j-1]= code[j]= 0;
		if (j== m){
			LShift(code, m);
		}
		hm[cur^1].push(Encode(code, m), hm[cur].dp[k]);
	}
}
void DpNum(int cur, int i, int j)
{
	int lf, up;
	const int num= bd[i][j];
	for (int k= 0; k< hm[cur].sizes; ++k){
		Decode(code, m, hm[cur].state[k]);
		lf= code[j-1];
		up= code[j];

		if (lf&&up){
			continue;
		}
		else if (num== lf || num== up){
			code[j-1]= code[j]= 0;
			if (j== m){
				LShift(code, m);
			}
			hm[cur^1].push(Encode(code, m), hm[cur].dp[k]+1);
		}
		else if (!lf && !up){
			if (j<m && (0== bd[i][j+1] || num== bd[i][j+1])){
				code[j-1]= 0;
				code[j]= num;
				hm[cur^1].push(Encode(code, m), hm[cur].dp[k]+1);
			}
			if (i<n && (0== bd[i+1][j] || num== bd[i+1][j])){
				code[j-1]= num;
				code[j]= 0;
				if (j== m){
					LShift(code, m);
				}
				hm[cur^1].push(Encode(code, m), hm[cur].dp[k]+1);
			}
		}
	}
}
int Solve()
{
	int cur= 0;
	int ans= 0;
	hm[cur].init();
	hm[cur].push(0, 0);

	for (int i= 1; i<= n; ++i){
		for (int j= 1; j<= m; ++j){
			hm[cur^1].init();
			if (!bd[i][j]){
				DpBlank(cur, i, j);
			}
			else if (1== bd[i][j]){
				DpBlock(cur, i, j);
			}
			else{
				DpNum(cur, i, j);
			}
			cur^= 1;
		}
	}

	for (int k= 0; k< hm[cur].sizes; ++k){
		ans+= hm[cur].dp[k];
	}

	if (ans> 0){
		ans-= 2;
	}

	return ans;
}
int main()
{
	while (~scanf("%d %d", &n, &m) && n){
		memset(bd, -1, sizeof(bd));
		for (int i= 1; i<= n; ++i){
			for (int j= 1; j<= m; ++j){
				scanf("%d", bd[i]+j);
			}
		}

		printf("%d\n", Solve());
	}
	return 0;
}
posted @ 2021-03-13 11:17  IdiotNe  阅读(67)  评论(0编辑  收藏  举报