uva10572 black&white 插头dp

终于切了第一道广义路径的题目,也确实感到比较复杂,最小表示法的优势也可以体现出来,因为这题,昨天的澡到现在才洗完,按照小hh的思路,用一条轮廓线记录联通状态,注意这里的轮廓线已经不是m+1啦,因为我们不需要左插头了,每个格子可以插至多4个插头,另外一条轮廓线表示当前的染色状态,这个要m+1因为还要保留左上格子的颜色,然后我们对于4个格子的颜色讨论,左,上,左上,当前,一共16中情况,8种是对称的,同时要注意一种情况,已经轮廓线上部已经有一个单独的联通块。说说我debug这么久是为什么吧,先是cs打成cl,问题是前4个sample尽然过啦,后面的sample爆了,后来发现改之,然后就开始纠结最后一个sample,对不上,一直到今天早上,我拿网上代码对拍,发现m=8的时候结果都不对,其他都是对的,查看代码数遍,直到刚刚,突然意识到,我的状态爆了,我最小表示法用二进制3位表示,范围0~7,我sb的从1开始标号,那么m=8时,12345678最大的标号就是这样,出现了8,坑爹了,改之,果然sample过了,提交1y,刷进了第一版

Ranking Submission Run Time Language Submission Date
5 10710525 0.360 C++ 2012-10-10 05:40:30

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=10007;
int pre[9][9][maxn];
bool res[9][9][maxn];
int bin[20],code[20];
struct node
{
	int size,head[maxn],next[maxn];
	LL sta[maxn],clo[maxn],sum[maxn];
	void clear()
	{
		memset(head,-1,sizeof(head));
		size=0;
	}
	void push(LL st,const LL v,LL cs,int x,int y,bool cl,int k)
	{
		int hash=((st*13)+cs)%maxn;
		for(int i=head[hash];i>=0;i=next[i])
		{
			if(sta[i]==st&&clo[i]==cs)
			{
				sum[i]+=v;
				return ;
			}
		}
		sta[size]=st,clo[size]=cs,sum[size]=v;
	    res[x][y][size]=cl,pre[x][y][size]=k;
		next[size]=head[hash],head[hash]=size++;
	}
}dp[2];
LL encode(int m)
{
	LL st=0,cnt=0;
	memset(bin,-1,sizeof(bin));
	for(int i=m-1;i>=0;i--)
	{
		if(bin[code[i]]==-1)
			bin[code[i]]=cnt++;
		code[i]=bin[code[i]];
		st<<=3;
		st|=code[i];
	}

	return st;
}
void decode(LL st,int m)
{
	for(int i=0;i<m;i++)
	{
		code[i]=st&7;
		st>>=3;
	}
}
int n,m,now,old;
char gp[20][20];
bool check(LL cs,int x,int y,int m,int nc)
{
	int cnt=0,cnt1=0;
	for(int i=0;i<m;i++)
	{
		if(code[i]==code[y])
			cnt++;
		if(((cs>>i)&1)==(nc^1))
			cnt1++;
	}
	if(cnt==1)
	{
		if(cnt1>1)
			return false;
		char ch=nc==1?'o':'#';
		for(int i=x-1;i<n;i++)
			for(int j=i==x-1?y+1:0;j<m;j++)
			{
				if(gp[i][j]==ch)
					return false;
				if(i+1<n&&j+1<m)
					return false;
			}
	}
	return true;
}
void DP(int x,int y,int nc)
{
	for(int k=0;k<dp[old].size;k++)
	{
		bool l=y==0?0:((dp[old].clo[k]>>(y-1))&1)==nc;
		bool up=x==0?0:((dp[old].clo[k]>>y)&1)==nc;
		bool lp=(x==0||y==0)?0:((dp[old].clo[k]>>m)&1)==nc;
		decode(dp[old].sta[k],m);
		if(x&&!up&&!check(dp[old].clo[k],x,y,m,nc))
			continue;
		if(!l&&!up&&!lp)
			code[y]=10;
		else if(l&&!up&&!lp)
			code[y]=code[y-1];
		else if(!l&&up&&!lp)
			code[y]=code[y];
		else if(!lp&&l&&up)
		{
			if(code[y-1]!=code[y])
			{
				for(int i=0,id=code[y];i<m;i++)
					if(code[i]==id)
						code[i]=code[y-1];
			}
		}
		else if(lp&&!up&&!l)
		{
			if(x==n-1&&y==m-1)
				continue;
			code[y]=10;
		}
		else if(lp&&l&&!up)
			code[y]=code[y-1];
		else if(lp&&up&&!l)
			code[y]=code[y];
		else continue;
		LL cs=dp[old].clo[k]&(~(1<<y))&(~(1<<m));
		if(nc) cs|=1<<y;
		if((up==0&&nc==0)||(up==1&&nc==1)) cs|=1<<m;
		dp[now].push(encode(m),dp[old].sum[k],cs,x,y,nc,k);
	}
}
void slove()
{
	dp[0].clear();
	dp[0].push(0,1,0,n,m,0,-1);
	now=0,old=1;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
		{
			old=now,now^=1,dp[now].clear();
			if(gp[i][j]!='#')
				DP(i,j,0);
			if(gp[i][j]!='o')
				DP(i,j,1);
		}
	int flag=-1,ans=0;
	for(int i=0;i<dp[now].size;i++)
	{
		decode(dp[now].sta[i],m);
		int cnt=0;
		memset(bin,-1,sizeof(bin));
		for(int j=0;j<m;j++)
		{
			if(bin[code[j]]==-1)
				bin[code[j]]=cnt++;
		}
		if(cnt<=2)
		{
			flag=i;
			ans+=dp[now].sum[i];
		}
	}
	if(flag==-1)
		puts("0\n");
	else
	{
		printf("%d\n",ans);
		for(int i=n-1;i>=0;i--)
			for(int j=m-1;j>=0;j--)
			{
				gp[i][j]=res[i][j][flag]==0?'o':'#';
				flag=pre[i][j][flag];
			}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
				printf("%c",gp[i][j]);
			puts("");
		}
		puts("");
	}
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);		
		for(int i=0;i<n;i++)
		{
			scanf("%s",gp[i]);
		}
		slove();
	}
	return 0;
}

                                        

你可能感兴趣的:(Date,dp,struct,ini,UP)