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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【SCOI2005】【BZOJ1087】互不侵犯King(状压dp)

發布時間:2023/12/18 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【SCOI2005】【BZOJ1087】互不侵犯King(状压dp) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

problem

  • 在N×N的棋盤里面放K個國王
  • 每個國王會攻擊它周圍的一圈共8個格子
  • 使他們互不攻擊,共有多少種擺放方案
  • N <= 9

solution

  • 用01串表示某一行放置的情況
  • 首先枚舉當前做到第幾行,以及當前一共放了幾顆棋子。
  • 于是狀態f[i][j][k]表示到第i行,一共放j個棋子(包括這之前的),且第i行的狀態是k的方案數。
  • 再考慮轉移。這一行肯定是由上一行的狀態轉移過來的,那么我們可以再枚舉上一行的狀態。
  • 很自然的,發現這會超時。每次枚舉一種狀態就需要2^9,兩重循環已經快爆掉了!我們可以發現一件事情。比如n=5,我們每次枚舉到的11111,11011,10111,01011這些狀態都是無效的。那么我們可以先預處理一下對于每一行的所有可行的狀態(就是不能有連續的1)。
  • 這樣的效率仍然不高——我們還可以對于每種可行的狀態i,j,預處理i和j是否能夠相鄰,這樣我們在DP的時候,就可以O(1)來轉移了。(這里也可以不預處理,每次直接判斷ij能否相鄰也可。)

最后,記得開long long。

codes

#include<iostream> using namespace std; const int maxn = 512; typedef long long LL; int c1[maxn], cnt[maxn], c2[maxn][maxn]; LL ans, f[10][100][maxn]; int main(){int n, m;cin>>n>>m;int all = (1<<n)-1;for(int i = 0; i <= all; i++){if((i&(i>>1))==0){c1[i] = 1;for(int x = i; x; x >>= 1) cnt[i]+= (x&1);}}for(int i = 0; i <= all; i++)if(c1[i])f[1][cnt[i]][i] = 1;for(int i = 1; i < n; i++){for(int j = 0; j <= all; j++)if(c1[j]){for(int k = 0; k <= all; k++)if(c1[k]){if(((j&k)==0)&&((j&(k>>1))==0)&&((j&(k<<1))==0)){for(int p = cnt[j]; p+cnt[k]<=m; p++)f[i+1][p+cnt[k]][k] += f[i][p][j];}}}}for(int i = 0; i <= all; i++)ans += f[n][m][i];cout<<ans<<"\n";return 0; }

轉載于:https://www.cnblogs.com/gwj1314/p/9444821.html

總結

以上是生活随笔為你收集整理的【SCOI2005】【BZOJ1087】互不侵犯King(状压dp)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。