日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

POJ - 2411 Mondriaan's Dream(状压dp)

發(fā)布時間:2024/4/11 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 POJ - 2411 Mondriaan's Dream(状压dp) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:鋪瓷磚

題目分析:經(jīng)典之經(jīng)典的狀態(tài)壓縮動態(tài)規(guī)劃,具體的懶得說了,怠惰ing。。一個月之前寫的代碼,還好當(dāng)時注釋做的好,現(xiàn)在稍微一看就能立馬理解,碼到博客上存著吧,三種方法,一種很巧妙很好寫但我至今不知道原理的大牛方法,一種很慢但很好理解的暴力枚舉法,還有一種效率很高不太容易寫的搜索方法,都掛上吧:

暴力枚舉:

#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=(1<<11)+100;int n,m;bool vis[N];LL dp[15][N];int b[15];bool check(int x) {while(x){if(x&1){x>>=1;if(!(x&1))return false;}x>>=1;}return true; }bool Check(int a,int b)//i,i-1 {int i=0;while(i<m){if((a&(1<<i))==0){if((b&(1<<i))==0)return false;elsei++;}elseif((b&(1<<i))==0)i++;else if(i==m-1||!((a&(1<<(i+1)))&&(b&(1<<(i+1)))))return false;elsei+=2;}return true; }int main() { // freopen("input.txt","r",stdin);for(int i=0;i<15;i++)//預(yù)處理 b[i]=1<<i;while(scanf("%d%d",&n,&m)!=EOF&&n+m){if(n<m)//始終保持m<n,保證高效(因為橫著豎著沒什么區(qū)別) swap(n,m);memset(dp,0,sizeof(dp));memset(vis,false,sizeof(vis));for(int i=0;i<b[m];i++)//嘗試第一行可行結(jié)果 {if(check(i)){vis[i]=true;dp[1][i]=1;}}for(int i=2;i<=n;i++)for(int j=0;j<b[m];j++)//第i列 for(int k=0;k<b[m];k++)//第i-1列 {if(Check(j,k))dp[i][j]+=dp[i-1][k];}cout<<dp[n][b[m]-1]<<endl;}return 0; }

大牛的剪枝法:

#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=(1<<11)+100;int n,m;bool vis[N];LL dp[15][N];int b[15];bool check(int x) {while(x){if(x&1){x>>=1;if(!(x&1))return false;}x>>=1;}return true; }int main() { // freopen("input.txt","r",stdin);for(int i=0;i<15;i++)//預(yù)處理 b[i]=1<<i;while(scanf("%d%d",&n,&m)!=EOF&&n+m){if(n<m)//始終保持m<n,保證高效(因為橫著豎著沒什么區(qū)別) swap(n,m);memset(dp,0,sizeof(dp));memset(vis,false,sizeof(vis));for(int i=0;i<b[m];i++)//嘗試第一行可行結(jié)果 {if(check(i)){vis[i]=true;dp[1][i]=1;}}for(int i=2;i<=n;i++)for(int j=0;j<b[m];j++)//第i列 for(int k=0;k<b[m];k++)//第i-1列 {if((j|k)!=b[m]-1)continue;if(!vis[j&k])continue;dp[i][j]+=dp[i-1][k];}cout<<dp[n][b[m]-1]<<endl;}return 0; }

效率最高的搜索:

#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=(1<<11)+100;int n,m;bool vis[N];LL dp[15][N];int b[15];bool check(int x) {while(x){if(x&1){x>>=1;if(!(x&1))return false;}x>>=1;}return true; }void dfs(int row,int col,int j,int k)//row:當(dāng)前行數(shù),col:當(dāng)前列數(shù),j:第i-1行狀態(tài),k:第i行狀態(tài) //通過第i行的狀態(tài)搜索第i-1行的狀態(tài) {if(col==m){dp[row][k]+=dp[row-1][j];return;}if(col>m)return;if(k&(1<<col))//若當(dāng)前位置為1 {dfs(row,col+1,j,k);//第col列是個豎著的,則不放 if(k&(1<<(col+1)))//第col列是個橫著的,則放 dfs(row,col+2,j|(1<<(col+1))|(1<<col),k);}else//若當(dāng)前位置為0,則上一行橫著豎著都行 dfs(row,col+1,j|(1<<col),k); }int main() { // freopen("input.txt","r",stdin);for(int i=0;i<15;i++)//預(yù)處理 b[i]=1<<i;while(scanf("%d%d",&n,&m)!=EOF&&n+m){if(n<m)//始終保持m<n,保證高效(因為橫著豎著沒什么區(qū)別) swap(n,m);memset(dp,0,sizeof(dp));memset(vis,false,sizeof(vis));for(int i=0;i<b[m];i++)//嘗試第一行可行結(jié)果 {if(check(i)){vis[i]=true;dp[1][i]=1;}}for(int i=2;i<=n;i++)for(int j=0;j<b[m];j++)dfs(i,0,0,j);cout<<dp[n][b[m]-1]<<endl;}return 0; }

?

超強干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

總結(jié)

以上是生活随笔為你收集整理的POJ - 2411 Mondriaan's Dream(状压dp)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。