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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Poj - 3254 Corn Fields (状压DP)(入门)

發(fā)布時間:2024/4/17 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Poj - 3254 Corn Fields (状压DP)(入门) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目鏈接:https://vjudge.net/contest/224636#problem/G

轉(zhuǎn)載于:https://blog.csdn.net/harrypoirot/article/details/23163485

?

題目大意:

農(nóng)夫有一塊地,被劃分為m行n列大小相等的格子,其中一些格子是可以放牧的(用1標(biāo)記),農(nóng)夫可以在這些格子里放牛,其他格子則不能放牛(用0標(biāo)記),并且要求不可以使相鄰格子都有牛。現(xiàn)在輸入數(shù)據(jù)給出這塊地的大小及可否放牧的情況,求該農(nóng)夫有多少種放牧方案可以選擇(注意:任何格子都不放也是一種選擇,不要忘記考慮!

?

解題分析就看上面那篇博客,我也是照著上面學(xué)的。

#include <cstdio> #include <cstring> using namespace std;#define mod 100000000 int M, N, top = 0; //top表示每行最多的狀態(tài)數(shù)int state[600]; //state存放每行所有的可行狀態(tài)(即沒有相鄰的狀態(tài))int dp[20][600]; //dp[i][j]:對于前i行數(shù)據(jù),第i行有前j種可能狀態(tài)時的解 int cur[20]; //cur[i]表示的是第i行整行的情況 inline bool ok(int x) { //判斷狀態(tài)x是否可行if (x&x << 1) return false;//若存在相鄰兩個格子都為1,則該狀態(tài)不可行return true; }void init() { //遍歷所有可能的狀態(tài)top = 0;int total = 1 << N; //遍歷狀態(tài)的上界for (int i = 0; i < total; ++i) { //總共有total種狀態(tài)需要討論if (ok(i))state[++top] = i; //state[]為一行中所有可行的狀態(tài) } }//原理就是,如果你在不能夠放1的位置放了1,那么這個方案肯定不可行 inline bool fit(int x, int k) { //判斷狀態(tài)x 與第k行的實際狀態(tài)的逆是否有‘重合’ //判斷理論上每一行能符合的情況是否與某一特定的行符合,因為每一行規(guī)定了能放1的位置if (x&cur[k])return false; //若有重合,(即x不符合要求)return true; //若沒有,則可行 }int main() {while (scanf("%d%d", &M, &N) != EOF) {init();memset(dp, 0, sizeof(dp));for (int i = 1; i <= M; ++i) {cur[i] = 0;int num;for (int j = 1; j <= N; ++j) { //輸入時就要按位來存儲,cur[i]表示的是第i行整行的情況,每次改變該數(shù)字的二進(jìn)制表示的一位scanf("%d", &num); //表示第i行第j列的情況(0或1)if (num == 0) //若該格為0 cur[i] += (1 << (N - j)); //則將該位置為1(注意要以相反方式存儲,即1表示不可放牧} //cur[]數(shù)組,利用狀態(tài)壓縮,用一維數(shù)組,表示了二維的數(shù)據(jù) }for (int i = 1; i <= top; i++) {if (fit(state[i], 1)) { //判斷所有可能狀態(tài)與第一行的實際狀態(tài)的逆是否有重合dp[1][i] = 1; //若第1行的狀態(tài)與第i種可行狀態(tài)吻合,則dp[1][i]記為1 }} //先算出第一行的情況,初始化dp[1][]的所有情況,方便下面dp的遞推,//前面的都是準(zhǔn)備工作,都是為了下面的這個狀態(tài)轉(zhuǎn)移方程做準(zhǔn)備for (int i = 2; i <= M; ++i) { //i索引第2行到第M行for (int k = 1; k <= top; ++k) { //該循環(huán)針對所有可能的狀態(tài),找出一組與第i行相符的state[k]if (!fit(state[k], i))continue; //判斷是否符合第i行實際情況for (int j = 1; j <= top; ++j) { //找到state[k]后,再找一組與第i-1行符合,且與第i行(state[])不沖突的狀態(tài)state[j]if (!fit(state[j], i - 1))continue; //判斷是否符合第i-1行實際情況 //找出上一行的所有可行狀態(tài)if (state[k] & state[j])continue; //判斷是否與第i行沖突 //判斷第i行的狀態(tài)是否與上一行沖突dp[i][k] = (dp[i][k] + dp[i - 1][j]) % mod; //若以上皆可通過,則將'j'累加到‘k'上 } //這里就相當(dāng)于dp[i][k]+=dp[i-1][j],只不過因為要取模運算,所以寫成這樣} //狀態(tài)轉(zhuǎn)移方程的根據(jù)為,dp[i][k]表示第i行采用方案k時,前i總共有多少種可行的情況 }int ans = 0;for (int i = 1; i <= top; ++i) { //累加最后一行所有可能狀態(tài)的值,即得最終結(jié)果!!!ans = (ans + dp[M][i]) % mod; }printf("%d\n", ans);} }

?

?

2018-07-26

?

轉(zhuǎn)載于:https://www.cnblogs.com/00isok/p/9370993.html

總結(jié)

以上是生活随笔為你收集整理的Poj - 3254 Corn Fields (状压DP)(入门)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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