刚学插头dp,跪求大佬帮忙调模板题
  • 板块学术版
  • 楼主边缘白鸟
  • 当前回复3
  • 已保存回复3
  • 发布时间2021/7/21 20:23
  • 上次更新2023/11/4 13:54:34
查看原帖
刚学插头dp,跪求大佬帮忙调模板题
185173
边缘白鸟楼主2021/7/21 20:23

这里是完整代码,有注释(虽然说感觉还是不是很完整啊)

#include <bits/stdc++.h>

using namespace std;

const int N = 14;
const int mod = 4001;

int n, m, endx, endy;

int now, last;

long long ans;

bool a[N][N];

int head[mod + 5], nxt[2 << 24], que[2][2 << 24], cnt[2], inc[N];

long long val[2][2 << 24];

char s[101];

inline void init ()
{
	scanf ("%d %d", &n, &m);
	for (int i = 1; i <= n; i ++)
	{
		scanf ("%s", s + 1);
		for (int j = 1; j <= m; j ++)
			if (s[j] == '.')
			{
				a[i][j] = 1;
				endx = i;
				endy = j;
			}
	}	
	inc[0] = 1;
	for (int i = 1; i <= 13; i ++)
		inc[i] = inc[i - 1] << 2; 
}

inline void insert (int bit, long long num)
{
	int u = bit % mod + 1;
	for (int i = head[u]; i; i = nxt[i])
		if (que[now][i] == bit)
		{
			val[now][i] += num;
			return ;
		}
	nxt[++ cnt[now]] = head[u]; // 这里采用挂表法  
	head[u] = cnt[now]; // 诶是不是和前向星很像  
	que[now][cnt[now]] = bit;
	val[now][cnt[now]] = num;
}

inline void work ()
{
	cnt[now] = 1; // hash 末指针  
	val[now][1] = 1; // 记录状态值 
	que[now][1] = 0; // 队列记录状态
//	last = 1;
//	insert (0, 1); 
	for (int i = 1; i <= n; i ++)
	{
		for (int j = 1; j <= cnt[now]; j ++)
			que[now][j] <<= 2;
		// 到每行第一个格子时在前面补一个空插头,剩下的部分从上一行最后一个格子那里直接搬过来
		for (int j = 1; j <= m; j ++)
		{
			memset (head, 0, sizeof (head)); // 清空 hash 
			last = now;
			now ^= 1;
			cnt[now] = 0; // 清空 hash
			for (int k = 1; k <= cnt[last]; k ++) // 枚举所有状态 
			{
				long long bit = que[last][k], num = val[last][k]; // 获取当前状态
				int p = (bit >> ((j - 1) * 2)) % 4, q = (bit >> (j * 2)) % 4;
				if (!a[i][j]) // 当前点有障碍 
					if (!p && !q)
						insert (bit, num);
				else if (!p && !q) // 无右插头,无下插头 
					if (a[i + 1][j] && a[i][j + 1]) // 左,上无障碍 
						insert (bit + inc[j - 1] + (inc[j] << 1), num); // 添加一个连通分量 
				else if (!p && q) // 无右插头,有下插头,情况三 
				{
					if (a[i][j + 1]) // 左无障碍  
						insert (bit, num);
					if (a[i + 1][j]) // 上无障碍  
						insert (bit - inc[j] * q + inc[j - 1] * q, num);
				}
				else if (p && !q) // 有右插头,无下插头,情况三  
				{
					if (a[i + 1][j]) // 上无障碍 
						insert (bit, num);
					if (a[i][j + 1]) // 左无障碍 
						insert (bit - inc[j - 1] * p + inc[j] * p, num);
				}
				// 有右插头,有下插头,情况二 
				else if (p == 1 && q == 1) // 情况 2 - 1 
				{
					int k1 = 1;
					for (int l = j + 1; l <= m; l ++)
					{
						if ((bit >> (l * 2)) % 4 == 1)
							k1 ++;
						if ((bit >> (l * 2)) % 4 == 2)
							k1 --;
						if (!k1)
						{
							insert (bit - inc[j] - inc[j - 1] - inc[l], num);
							break;
						}
					}
				}
				else if (p == 2 && q == 2) // 情况 2 - 2 
				{
					int k1 = 1;
					for (int l = j - 2; l >= 0; l --)
					{
						if ((bit >> (l * 2)) % 4 == 1)
							k1 --;
						if ((bit >> (l * 2)) % 4 == 2)
							k1 ++;
						if (!k1)
						{
							insert (bit - (inc[j] << 1) - (inc[j - 1] << 1) + inc[l], num);
							break;
						}
					}
				}
				else if (p == 2 && q == 1) // 情况 2 - 4
					insert (bit - (inc[j - 1] << 1) - inc[j], num);
				else if (i == endx && j == endy) // 情况 2 - 3
					ans += num; 
			} 
		}
	}
}

int main ()
{
	init ();
	work ();
	printf ("%lld", ans);
}
2021/7/21 20:23
加载中...