POJ 2411 Mondriaan's Dream 据说超时可以打表^

    xiaoxiao2025-07-21  7

    题目:Mondriaan's Dream

    状态压缩,超时,于是花2分钟打个表<( ̄︶ ̄)>

    思路:(虽然超时。。。)

        0 表示没有覆盖      1 表示已经覆盖      dp[i][s] 表示第 i 行使用状态 s 的方案数            dp[i][s] = ∑dp[i-1][ss] ss 为 枚举的第 i-1行的情况            注意:      1. ss 中的0表示没有覆盖 ,需要第 i 行在此处放一块 竖着的砖      所以 s 和 ss 不能在相同的位置同时为 0      即当 ss 在某处是 0的话 s在该处必须是 1 且只能竖着放      2. ss 中的1表示已经覆盖 ,故第 i 行在此处可以选择放(1)一块横着的砖或者不放(0)      如果放横着的砖,需要两个连续的1,同时上一行也要有2个连续的1      比如 ss 是 010 的时候,s 取任意值都是不合理的            PS : 1*2 的小矩形拼出来的面积必然为偶数      若 h*w 为奇数   puts("0")  

    AC代码:

    #define mem(a,x) memset(a,x,sizeof(a)) #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<stack> #include<cmath> #include<map> #include<stdlib.h> #include<cctype> #include<string> #define Sint(n) scanf("%d",&n) #define Sll(n) scanf("%I64d",&n) #define Schar(n) scanf("%c",&n) #define Sint2(x,y) scanf("%d %d",&x,&y) #define Sll2(x,y) scanf("%I64d %I64d",&x,&y) #define Pint(x) printf("%d",x) #define Pllc(x,c) printf("%I64d%c",x,c) #define Pintc(x,c) printf("%d%c",x,c) using namespace std; typedef long long ll; /* 0 表示没有覆盖 1 表示已经覆盖 dp[i][s] 表示第 i 行使用状态 s 的方案数 dp[i][s] = ∑dp[i-1][ss] ss 为 枚举的第 i-1行的情况 注意: 1. ss 中的0表示没有覆盖 ,需要第 i 行在此处放一块 竖着的砖 所以 s 和 ss 不能在相同的位置同时为 0 即当 ss 在某处是 0的话 s在该处必须是 1 且只能竖着放 2. ss 中的1表示已经覆盖 ,故第 i 行在此处可以选择放(1)一块横着的砖或者不放(0) 如果放横着的砖,需要两个连续的1,同时上一行也要有2个连续的1 比如 ss 是 010 的时候,s 取任意值都是不合理的 PS : 1*2 的小矩形拼出来的面积必然为偶数 若 h*w 为奇数 puts("0") */ ll ans[12][12] = {{0,1,0,1,0,1,0,1,0,1,0},{1,2,3,5,8,13,21,34,55,89,144},{0,3,0,11,0,41,0,153,0,571,0},{1,5,11,36,95,281,781,2245,6336,18061,51205},{0,8,0,95,0,1183,0,14824,0,185921,0},{1,13,41,281,1183,6728,31529,167089,817991,4213133,21001799},{0,21,0,781,0,31529,0,1292697,0,53175517,0},{1,34,153,2245,14824,167089,1292697,12988816,108435745,1031151241,8940739824},{0,55,0,6336,0,817991,0,108435745,0,14479521761,0},{1,89,571,18061,185921,4213133,53175517,1031151241,14479521761,258584046368,3852472573499},{0,144,0,51205,0,21001799,0,8940739824,0,3852472573499,0}}; int main() { int h,w; while (Sint2(h,w)==2) { if (h==0&&w==0) break; Pllc(ans[w-1][h-1],'\n'); } return 0; }

    TLE代码:

    #define mem(a,x) memset(a,x,sizeof(a)) #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<stack> #include<cmath> #include<map> #include<stdlib.h> #include<cctype> #include<string> #define Sint(n) scanf("%d",&n) #define Sll(n) scanf("%I64d",&n) #define Schar(n) scanf("%c",&n) #define Sint2(x,y) scanf("%d %d",&x,&y) #define Sll2(x,y) scanf("%I64d %I64d",&x,&y) #define Pint(x) printf("%d",x) #define Pllc(x,c) printf("%I64d%c",x,c) #define Pintc(x,c) printf("%d%c",x,c) using namespace std; typedef long long ll; /* 0 表示没有覆盖 1 表示已经覆盖 dp[i][s] 表示第 i 行使用状态 s 的方案数 dp[i][s] = ∑dp[i-1][ss] ss 为 枚举的第 i-1行的情况 注意: 1. ss 中的0表示没有覆盖 ,需要第 i 行在此处放一块 竖着的砖 所以 s 和 ss 不能在相同的位置同时为 0 即当 ss 在某处是 0的话 s在该处必须是 1 且只能竖着放 2. ss 中的1表示已经覆盖 ,故第 i 行在此处可以选择放(1)一块横着的砖或者不放(0) 如果放横着的砖,需要两个连续的1,同时上一行也要有2个连续的1 比如 ss 是 010 的时候,s 取任意值都是不合理的 PS : 1*2 的小矩形拼出来的面积必然为偶数 若 h*w 为奇数 puts("0") */ ll dp[12][1<<12]; int h,w; ll ans[12][12]; bool ok(int st) { int dig[22]; int len = 0; while (st) { dig[++len] = st&1; st>>=1; } for (int i = 1;i <= len;++i) { int t = 0; while (i <= len&&dig[i] == 1)//第一行被覆盖的必然是 横着放的砖 { ++i;++t; } if (t > 0) { --i; if (t&1) return 0;//横着放的砖连续段必须是偶数 } } return 1; } bool check(int s1,int s2)//检查当前行和上一行是否矛盾 { int b1[20] = {0}; int b2[20] = {0}; for (int i = 0;i < w;++i)//获取状态 { b1[i] = s1&(1<<i); b2[i] = s2&(1<<i); } //若上一行为0,当前行必须为1 for (int i = 0;i < w;++i) { if (b2[i]==0&&b1[i] == 0) return 0; } //若上一行和当前行都为1,表示当前行是放的横砖 for (int i = 0;i < w;++i) { int t = 0; while (i < w&&b1[i]&&b2[i]) { ++i;++t; } if (t > 0) { --i; if (t&1) return 0; } } return 1; } int main() { mem(ans,-1); while (Sint2(h,w) == 2) { if (h == 0&&w == 0) break; if (w > h) swap(w,h); if (~ans[w][h]) { Pllc(ans[w][h],'\n'); continue; } else if ((w*h)&1) { ans[w][h] = 0; } else if (h == 1) { ans[w][h] = 1; } else { int V = (1<<w) - 1; mem(dp,0); for (int i = 0;i <= V;++i)//初始化第一行的情况 { if (ok(i)) { dp[1][i] = 1; // cout<<"state = "<<i<<endl; } else dp[1][i] = 0; } for (int i = 2;i <= h;++i)//枚举后面的行 { for (int j = 0;j <= V;++j)//枚举当前行的状态 { for (int k = 0;k <= V;++k)//枚举上一行的情况 { if (check(j,k)) { dp[i][j] += dp[i-1][k]; // cout<<"state[i] = "<<j<<" state[i-1] = "<<k<<endl; // cout<<"dp = "<<dp[i][j]<<endl; } } } } ans[w][h] = dp[h][V];//第h行要铺满啊! } Pllc(ans[w][h],'\n'); } return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-1300927.html
    最新回复(0)