从昨天下午写到现在,终于算是A了,实在是很郁闷啊!
这道题看到能想到的就是状态压缩dp了,刚开始写了一个很暴力的,开了两个数组,dp1[i][j]用来记录第i行头朝上的,dp2[i][j]用来记录第i行头朝下的,然后位运算按照条件进行dp的,超时就不用说了,但是一直wa就让我很郁闷啊!!改了一个晚上,还是那样,然后看了别人的题解说只开一个数组只记录头朝下的进行判断,然后又写但是只解决了超时的问题,然后的然后,想想换个记录三角形头朝上的,因为那样最后求了一半的时候合起来比较好判断,然后竟然ac啦!高兴啊,但是那个为什么错就不知道了。。。
思路:dp[i][j]用来记录第i行三角形头朝上状态为j的一共的个数,dp[i][j]+=dp[i-1][k]如果状态j和上一行的状态k相容,在这里我是用一个函数进行判断的,是将数据拆成一位一位的然后进行判断。最后sum+=dp[2*n][i]*dp[2*n][i];因为上面的半边合下面的半边完全相同,就可以直接简化了,下面是代码!
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<climits>
#include<map>
using namespace std;
#define rep(i,n) for(int i=0; i<n; i++)
#define repf(i,n,m) for(int i=(n); i<=(m); ++i)
#define repd(i,n,m) for(int i=(n); i>=(m); --i)
#define ll long long
#define arc(a) ((a)*(a))
#define inf 100000
#define exp 0.000001
#define N 1<<13
ll dp[20][N];
bool fun(int n,int x,int y)
{
int sign=-1;//sign用来记录这一位的前一个状态的。
int flag=true;
rep(i,n)
{
int m=(y>>i)&1;
if(m==1 && sign==-1)
{
sign=(x>>i)&1;
if(i==n-1 || sign==0) flag=false;
sign=-1;
}
else if(m==1 && sign==1)
{
sign=(x>>i)&1;
}
else if(m==1 && sign==0)
{
sign=(x>>i)&1;
if(sign==0 || i==n-1) flag=false;
sign=-1;
}
else if(m==0 && sign==-1)
{
sign=(x>>i)&1;
}
else if(m==0 && sign==1)
{
flag=false;
}
else if(m==0 && sign==0)
sign=(x>>i)&1;
if(flag==false)
return flag;
}
return true;
}
int main()
{
int n;
int test=0;
while(cin>>n)
{
if(test!=0) printf("\n");
test++;
memset(dp,0,sizeof(dp));
dp[n][(1<<n)-1]=1;
repf(i,n+1,2*n)
{
rep(j,1<<(i-1))//shang
{
if(dp[i-1][j]==0) continue;
rep(k,1<<i)//下
{
if(fun(i,j,k))//判断两种状态是否相容
{
dp[i][k]+=dp[i-1][j];
}
}
}
}
ll sum=0;
rep(i,1<<(2*n))
rep(j,1<<(2*n))
if((i^j)==0)
sum+=dp[2*n][i]*dp[2*n][j]; //求到一半直接简化
cout<<sum<<endl;
}
return 0;
}