【題解】玲瓏學院oj1089 Place the Tiles

題目鏈接

題意:用1×2的骨牌來鋪帶障礙格的矩形網格,使得每個網格至多被一張骨牌覆蓋且無法再加入骨牌(即沒有相鄰的未覆蓋無障礙網格)。求需要的最少骨牌數。

分析:輪廓線dp。每個格子的狀態用一個4進制數來表示,0代表未覆蓋,1代表已覆蓋且由骨牌右端或下端覆蓋,2代表已覆蓋且由骨牌左端覆蓋,3代表已覆蓋且由骨牌上端覆蓋。轉移按如下分類進行:

        1.障礙格:將當前格狀態改成1

        若不是情形1

        2.左格(存在)狀態爲2或上格狀態爲3:將當前格狀態改成1

        若不是情形1且不是情形2

        3.考慮當前格狀態是否可爲2或3

        4.考慮當前格是否可以不放骨牌

代碼

#include<bits/stdc++.h>
using namespace std;
const int maxS=1<<20;
struct node
{
	vector<int> sta,f;
	int mp[maxS];
	void clear()
	{
		for (int i=0;i<sta.size();i++)
		{
			int S=sta[i];
			mp[S]=-1;
		}
		sta.clear();f.clear();
	}
	void updata(int S,int f0)
	{
		int k=mp[S];
		if (k!=-1) f[k]=min(f[k],f0);
		else
		{
			sta.push_back(S);
			f.push_back(f0);
			k=sta.size();
			mp[S]=k-1;
		}
	}
}nd[2];
int n,m,one[20],two[20],three[20];
char ch[200][20];
void init()
{
	for (int i=0;i<2;i++) memset(nd[i].mp,-1,sizeof(nd[i].mp));
	for (int i=1;i<=10;i++) one[i]=1<<(2*i-2),two[i]=1<<(2*i-1),three[i]=one[i]^two[i];
}
int get(int S,int j)
{
	return (S&three[j])>>(2*j-2);
}
int make(int S,int j,int p)
{
	S|=three[j];
	if (p==0) return S^three[j];
	if (p==1) return S^two[j];
	if (p==2) return S^one[j];
	return S;
}
int main()
{
	init();
	int T;cin>>T;
	while (T--)
	{
		scanf("%d%d",&n,&m);
		for (int i=1;i<=n;i++) scanf("%s",ch[i]+1);
		int S0=0,pre=0,now=1;
		for (int i=1;i<=m;i++) S0^=one[i];
		nd[now].clear();nd[now].updata(S0,0);
		for (int i=1;i<=n;i++)
		    for (int j=1;j<=m;j++)
		    {
		    	swap(pre,now);nd[now].clear();
		    	for (int k=0;k<nd[pre].sta.size();k++)
		    	{
		    		int S=nd[pre].sta[k],f=nd[pre].f[k];
		    		if (ch[i][j]=='*')
		    		{
		    			int S1=make(S,j,1);
		    			nd[now].updata(S1,f);
					}
					else
					{
						bool flag=0;
						if (j>1&&get(S,j-1)==2)
						{
							flag=1;
							int S1=make(S,j,1);
							nd[now].updata(S1,f);
						}
						if (get(S,j)==3)
						{
							flag=1;
							int S1=make(S,j,1);
							nd[now].updata(S1,f);
						}
						if (flag) continue;
						if (j<m&&ch[i][j+1]=='.'&&get(S,j+1)!=3)
						{
							int S1=make(S,j,2);
							nd[now].updata(S1,f+1);
						}
						if (i<n&&ch[i+1][j]=='.')
						{
							int S1=make(S,j,3);
							nd[now].updata(S1,f+1);
						}
						if ((j==1||get(S,j-1))&&get(S,j))
						{
							int S1=make(S,j,0);
							nd[now].updata(S1,f);
						}
					}
				}
			}
		int ans=n*m;
		for (int k=0;k<nd[now].f.size();k++) ans=min(ans,nd[now].f[k]);
		printf("%d\n",ans);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章