hdu 4064 Carcassonne

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4064

/*福州网络赛的一道题,很容易看出状态压缩DP,当时用四进制写的,没能做出来,感觉会超时,赛后看别人的解题报告,可以记录上面的状态和下面的状态然后用三进制实现。

不过要加一些剪枝,比如:对于四面都一样的瓷块,只需算出一种状态,然后乘以4。这是个很有力的剪枝。*/

4730663 2011-10-10 10:15:52 Accepted 4064 328MS 9640K 1382 B C++ zyzamp

这次写的方法和以前写的不同,以前都是枚举每一个状态,直接for循环搞定,而这个不能直接枚举状态,因为有的状态不存在,或者有的存在但是上下界不容易确定。

所以要用dfs,dfs结束确定一种状态。

code:

# include<stdio.h>

# include<string.h>

# define N 600000

# define mod 1000000007

int n,m;

__int64 dp[2][N],sum;

char map[15][15][5];

int a[200],tag,flag;

int s[15];

void DFS(int r,int up,int down,int num,int right)

{

	int xx,rr,yy,ll,i;

	if(num==m)

	{

		if(r==0) dp[flag][down]+=tag;

		else

		{

			dp[flag][down]+=dp[(flag+1)%2][up]*tag;

			dp[flag][down]%=mod;

		}

		return;

	}

	for(i=1;i<4;i++)

		if(map[r][num][i]!=map[r][num][0]) break;

	if(i==4)

	{

		tag*=4;

		xx=a[map[r][num][0]];

		if(xx==right || right==-1) DFS(r,up*3+xx,down*3+xx,num+1,xx);

		tag/=4;

		return;

	}

	for(i=0;i<4;i++)

	{

		xx=a[map[r][num][i]];

		rr=a[map[r][num][(i+1)%4]];

		yy=a[map[r][num][(i+2)%4]];

		ll=a[map[r][num][(i+3)%4]];

		if(right==-1 || ll==right) DFS(r,up*3+xx,down*3+yy,num+1,rr);

	}

}

int main()

{

	int i,j,ncase,t;

	scanf("%d",&ncase);

	a['F']=0;

	a['C']=1;

	a['R']=2;

	s[0]=1;

	for(i=1;i<=12;i++)

		s[i]=s[i-1]*3;

	for(t=1;t<=ncase;t++)

	{

		scanf("%d%d",&n,&m);

		for(i=0;i<n;i++)

			for(j=0;j<m;j++)

				scanf("%s",map[i][j]);

		flag=0;

		memset(dp,0,sizeof(dp));

		for(i=0;i<n;i++)

		{

			tag=1;

			flag=(flag+1)%2;

			DFS(i,0,0,0,-1);

			for(j=0;j<s[m];j++) dp[(flag+1)%2][j]=0;

		}

		sum=0;

		for(i=0;i<s[m];i++)

		{

			sum+=dp[flag][i];

			sum%=mod;

		}

		printf("Case %d: %I64d\n",t,sum);

	}

	return 0;

}

 

你可能感兴趣的:(SSO)