强烈推荐网址:http://www.notonlysuccess.com/?p=931
多回路的不用判联通状态,二进制即可,转移情况2*2种。 时间O(n*m*2^n) 空间O(n*2^n)
/**插头DP**/
#include <cstdio>
#include <cstring>
const int maxm=13 ;
const int maxn=1<<12;
typedef long long ll ;
ll dp[maxm][maxn];
int map[maxm][maxm];
/*
i行j列 轮廓线状态k。除了换行以外,每个状态只与同行的状态的前一列有关,可以减少一维空间
*/
int main ()
{
int n,m;
int cas;
scanf("%d",&cas);
for (int I=1 ; I<=cas ; ++I)
{
int cnt=0;
scanf("%d%d",&n,&m);
/*行列交换的优化、以及总可行格数为奇数的优化*/
if(n>=m)
for (int i=0 ; i<n ; ++i)
{
for (int j=1 ; j<=m ; ++j)
{
scanf("%d",&map[i][j]);
if(map[i][j])cnt++;
}
}
else
{
n^=m^=n^=m;
for (int i=1 ; i<=m ; ++i)
{
for (int j=0 ; j<n ; ++j)
{
scanf("%d",*(map+j)+i);
if(map[j][i])cnt++;
}
}
}
if(cnt&1)
{
printf("Case %d: There are 0 ways to eat the trees.\n",I);
continue;
}
memset (dp , 0 , sizeof(dp));
dp[0][0]=1;
for (int i=0 ; i<n ; ++i)
{
if(i>0)
for (int k=0 ; k<(1<<(m)) ; ++k)
{
dp[0][k<<1]=dp[m][k];//换行
//printf("%d %d %o map==%d %lld\n",i,0,k,map[i][0],dp[i][0][k<<1]);
}
for (int j=1 ; j<=m ; ++j)
{
for (int k=0 ; k<(1<<(m+1)) ; ++k)
{
int a=(1<<j);
int b=(1<<(j-1));
if(map[i][j])
{
dp[j][k]=dp[j-1][k^a^b];
if((!(k&a)) ^ (!(k&b)))dp[j][k]+=dp[j-1][k];
}
else
{
if((!(k&a)) && (!(k&b)))
{
dp[j][k]=dp[j-1][k];
}
else dp[j][k]=0;
}
}// end for k
}//end for j
}// end for i
//for (int i=0 ; i<(1<<(m+1)) ; ++i)
//printf("%d\n" , dp[n-1][m-1][i]);
printf("Case %d: There are %I64d ways to eat the trees.\n",I,dp[m][0]);
}
return 0;
}
时间O(n*m*2^n) 空间O(2^n)
/**插头DP**/
#include <cstdio>
#include <cstring>
const int maxm=13 ;
const int maxn=1<<12;
typedef long long ll ;
ll dp[2][maxn];
int map[maxm][maxm];
/*
i行j列 轮廓线状态k。除了换行以外,每个状态只与同行的状态的前一列有关,可以减少一维空间
*/
int main ()
{
int n,m;
int cas;
scanf("%d",&cas);
for (int I=1 ; I<=cas ; ++I)
{
int cnt=0;
scanf("%d%d",&n,&m);
/*行列交换的优化、以及总可行格数为奇数的优化*/
if(n>=m)
for (int i=0 ; i<n ; ++i)
{
for (int j=1 ; j<=m ; ++j)
{
scanf("%d",&map[i][j]);
if(map[i][j])cnt++;
}
}
else
{
n^=m^=n^=m;
for (int i=1 ; i<=m ; ++i)
{
for (int j=0 ; j<n ; ++j)
{
scanf("%d",*(map+j)+i);
if(map[j][i])cnt++;
}
}
}
if(cnt&1)
{
printf("Case %d: There are 0 ways to eat the trees.\n",I);
continue;
}
memset (dp , 0 , sizeof(dp));
dp[0][0]=1;
int t=1;
for (int i=0 ; i<n ; ++i)
{
memset (dp[t] , 0 , sizeof(dp[t]));//必须清空
if(i>0)
{
for (int k=0 ; k<(1<<(m)) ; ++k)
{
dp[t][k<<1]=dp[t^1][k];//换行
}
t^=1;
}
for (int j=1 ; j<=m ; ++j,t^=1)
{
for (int k=0 ; k<(1<<(m+1)) ; ++k)
{
int a=(1<<j);
int b=(1<<(j-1));
if(map[i][j])
{
dp[t][k]=dp[t^1][k^a^b];
if((!(k&a)) ^ (!(k&b)))dp[t][k]+=dp[t^1][k];
}
else
{
if((!(k&a)) && (!(k&b)))
{
dp[t][k]=dp[t^1][k];
}
else dp[t][k]=0;
}
//printf("%d %d %o %I64d %I64d\n" , i , j ,k,dp[t^1][k] , dp[t][k]);
}// end for k
}//end for j
}// end for i
//printf("%I64d\n" , dp[t][0]);
printf("Case %d: There are %I64d ways to eat the trees.\n",I,dp[t^1][0]);
}
return 0;
}
Rank | Author | Exe. Time | Exe. Memory | Code Len. | Language | Date |
1 | Geners | 0MS | 256K | 2361B | G++ | 2011-10-15 16:55:39 |
比赛的时候一直纠结在4进制上 , 上下左右四个方向表示状态,没敢敲,怕超时, 后来看见达哥过了 , 问了下方法,原来是可以3进制的,只考虑F R C即可,当时比赛的时候脑子木了。
在看了fzq的代码之前 ,第一行状态和第一列状态都是特殊处理的,在fzq的代码里有个技巧,因为是4进制表示3进制,所有有一个冗余态,直接让这个状态表示万能态,即任何时候都能与其联通,于是代码简洁了不少 , 时间也快了 。
哈希表+4进制+位运算+轮廓线状态。
哈希表要尽量小一些, 时间都浪费在滚动数组的清空了。
TLE+MLE代码 , 没用哈希的纯映射方法, 空间各种浪费啊
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1594324;//3^13=1594323;
const int mod = 1000000007;
int val[maxn];
int dir[4][4]={1, 2, 3, 0, 0, 1, 2, 3, 2, 3, 0, 1, 3, 0, 1, 2};// dir[][0-up 1-right 2-down 3-left];
int dp[2][45108864+123];//00 - F , 01 - C , 10 - R , 11 is redundancy
char map_[13][13][5];
int t; //滚动用
void init()//put ternary in quaternary
{
int cnt = 0;
val[cnt++] = 0;
val[cnt++] = 1;
val[cnt++] = 2;
int p = 1;
while (cnt < maxn)
{
val[cnt++] = val[p]*4 + val[0];
val[cnt++] = val[p]*4 + val[1];
val[cnt++] = val[p++]*4 + val[2];
}
}
inline int change(char ch)
{
if(ch == 'F')return 0;
if(ch == 'C')return 1;
if(ch == 'R')return 2;
return 100;
}
int r,c;
void dfs(int col, int sta, int uni)//
{
if(col==0)
{
//printf("===sta===%d\n",sta);
dp[0][sta]=(1+dp[0][sta])%mod;
return ;
}
for (int i = 0; i < 4; ++i)
{
const char *str=map_[0][col-1];//
//printf("%s",map_[0][col]);
//printf("%d %d dir==%d %c\n",change(str[dir[i][3]]), uni, dir[i][3], str[dir[i][3]] );
if( change(str[dir[i][1]])==uni )
dfs(col-1 , (sta<<2)|(change(str[dir[i][2]])) , change(str[dir[i][3]]));
}
}
int cuts;
void DP()
{
t=0;
for (int i=1 ; i<r ; ++i)
{
t^=1;
memset (dp[t] , 0 , sizeof(dp[t]));
for (int k=0 ; val[k]<=(1<<((c<<1)+2)) ; ++k)
{
dp[t][((val[k] & cuts)<<2) |3]=(dp[t^1][val[k]]+dp[t][((val[k] & cuts)<<2) |3])%mod;
//printf("===%d %d %d %d %d\n", i , j , val[k] , (val[k]<<2 & cut[c]) , cut[c]);
}
for (int j=0 ; j<c ; ++j)
{
const char *str=map_[i][j];
t^=1;
memset (dp[t] , 0 , sizeof(dp[t]));
if(j==0)
{
for (int k=0 ; val[k]<=(1<<(c<<1)+2) ; k+=3)
if((val[k]&3)==0)
{
int state=((val[k]>>2) & 3);
for (int d=0 ; d<4 ; ++d)
{
if(change(str[dir[d][0]])==state)
dp[t][ (val[k]&(~15)) | (change(str[dir[d][1]])<<2)
| change(str[dir[d][2]]) ]=(dp[t^1][val[k]|3]+dp[t][ (val[k]&(~15)) | (change(str[dir[d][1]])<<2)
| change(str[dir[d][2]]) ])%mod;
}
}
}
else
{
for (int k=0 ; val[k]<=( 1<<((c<<1)+2) ) ; ++k)
{
//if(!dp[j-1][val[k]])continue;
//printf("===%d %d %d %s\n", i , j , val[k] ,str);
int sta=val[k];
int left=(val[k]>>(2*j) & 3);
int up=(val[k]>>(2*j+2) & 3);
//sta=sta^(left<<(2*j))^left<<
//printf("%s %d %d %d %d\n",str,i,j ,c , k);
//printf("val==%d left ==%d up==%d dp===%d j==%d\n",val[k], left , up , dp[i][j-1][val[k]] , j);
if(dp[t^1][val[k]])
for (int d=0 ; d<4 ; ++d)
{
if( change(str[dir[d][0]])==up && change(str[dir[d][3]])==left )
dp[t][ val[k]&(~(15<<(j*2))) | (change(str[dir[d][2]])<<(2*j))
| change(str[dir[d][1]])<<(2*j+2) ] =
(dp[t^1][val[k]]+dp[t][ val[k]&(~(15<<(j*2))) | (change(str[dir[d][2]])<<(2*j))
| change(str[dir[d][1]])<<(2*j+2) ] )%mod;
//printf("option ==%d %d\n" , val[k]&(~(15<<(j*2))) | (change(str[dir[d][2]])<<(2*j))
//| change(str[dir[d][1]])<<(2*j+2) , dp[i][j-1][val[k]]);
}
}
}
}
}
}
int main ()
{
init();
int cas;
scanf("%d", &cas);
for (int I=1 ; I<=cas ; ++I)
{
scanf("%d%d", &r, &c);
cuts=(1<<(c<<1))-1;
for (int i = 0; i < r; ++i)
for (int j = 0; j < c; ++j)
scanf("%s", map_[i][j]);
memset (dp, 0, sizeof(dp));
dfs(c , 0 , 0);//DFS要倒着来,这样DP的时候能是正着的
dfs(c , 0 , 1);
dfs(c , 0 , 2);
int ans=0;
DP();
for (int i=0 ; val[i]<=(1<<((c<<1)+2)) ; ++i)
if(dp[t][val[i]])
{
ans=(dp[t][val[i]]+ans)%mod;
//printf("val ==%d dp==%d\n",val[i],dp[r-1][c-1][val[i]]);
}
printf("Case %d: %d\n",I,ans);
}
return 0;
}
#include <cstdio>
#include <cstring>
typedef int types;
using namespace std;
const int Limithash=100007;
const int mod=1000000007;
int dir[4][4]={1, 2, 3, 0, 0, 1, 2, 3, 2, 3, 0, 1, 3, 0, 1, 2};
int r, c, map[5];
int cuts;
int t;
struct Hashmap{
int hash[Limithash], state[Limithash], sum[Limithash], total;
void hash_in(types s, int data)
{
int pos=s%Limithash;//Limithash must be a prime
while (hash[pos])
{
if(state[hash[pos]]==s)//如果状态存在
{
sum[hash[pos]]=(sum[hash[pos]]+data)%mod;
return;//找到并更新状态
}
pos++;
if(pos==Limithash)pos=0;
}
total++;//从1开始
hash[pos]=total;//此处添加新状态
state[total]=s;
sum[total]=data;
}
void clear ()
{
total=0;
memset (hash , 0 , sizeof(hash));
}
}dp[2];
inline void roll ()
{
t^=1;
dp[t].clear();
}
inline bool valid(int x, int y)
{
return x==0 || x==y;
}
char str[10];
int main ()
{
int cas;
scanf("%d", &cas);
for (int I=1 ; I<=cas ; ++I)
{
scanf("%d%d", &r, &c);
cuts=(1<<(c<<1))-1;
t=0;
dp[0].clear();
dp[0].hash_in(0, 1);
for (int i=0 ; i<r ; ++i)
{
roll();
for (int k=1 ; k<=dp[t^1].total ; ++k)//换行
dp[t].hash_in( (dp[t^1].state[k] & cuts)<<2, dp[t^1].sum[k]);
for (int j=0 ; j<c ; ++j)
{
roll();
scanf("%s", str);
for (int k=0 ; k<4 ; ++k)
{
if(str[k]=='C')map[k]=1;
if(str[k]=='F')map[k]=2;
if(str[k]=='R')map[k]=3;
}
for (int k=1 ; k<=dp[t^1].total ; ++k)
{
int sta=dp[t^1].state[k];
int left=(sta>>(j<<1))&3;
int up=(sta>>((j<<1)+2))&3;
sta=sta^(left<<(j<<1))^(up<<((j<<1)+2));
for (int d=0 ; d<4 ; ++d)
{
if(valid(left, map[dir[d][3]]) && valid(up, map[dir[d][0]]))
dp[t].hash_in( sta|(map[dir[d][1]]<<(j+1<<1))|(map[dir[d][2]]<<(j<<1)),
dp[t^1].sum[k]);
}
}
}
}
int ans=0;
for (int i=1 ; i<=dp[t].total ; ++i)
{
ans=(ans+dp[t].sum[i])%mod;
}
printf("Case %d: %d\n", I, ans);
}
return 0;
}