1. 程式人生 > >bzoj 1087 [SCOI2005] 互不侵犯King

bzoj 1087 [SCOI2005] 互不侵犯King

沒有 code desc name back open 進行 -a 不用

1087: [SCOI2005]互不侵犯King

2017-08-24

Description

  在N×N的棋盤裏面放K個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上
左下右上右下八個方向上附近的各一個格子,共8個格子。


Input

  只有一行,包含兩個數N,K ( 1 <=N <=9, 0 <= K <= N * N)


Output

  方案數。


Sample Input

3 2

Sample Output

16
數據n很小,(1<=n<=9)這樣就很容易就想到暴力dfs,在方塊中枚舉每一個king在哪裏(但
當k大約到50時大約就是50!的計算量,不T才怪qwq); 這樣就換一個思路的說? 對於每一個位置,都是可以用1|0表示(0表示沒有選這個位置,1表示選(有king)) 這樣能把一行的信息壓縮成一個數x;這就是所謂的狀壓dp 枚舉每一行的信息然後轉移,然後就過了的說 然後c[i]表示i這個數是否自己和本身發生沖突 c2[i][j]表示i與j不發生沖突->具體就是i和j,j和i左移一位,i和j左移一位不沖突(所有按位與運算等於0) cnt記錄這個數用了幾個1; 其實c[i]只是對循環進行優化而已,就是這樣的說 技術分享
#include<iostream>
using namespace std;
const int maxn=1<<11; int n,k,cnt[maxn]; bool c[maxn],c2[maxn][maxn]; int tot; long long ans,dp[10][100][maxn]; void df(){ for(int i=0;i<=tot;i++){ int s=0; if((i&(i>>1))==0){ for(int j=i;j;j=j>>1)s+=(j&1); c[i]=1;cnt[i]=s; } }
for(int i=0;i<=tot;i++)if(c[i]) for(int j=0;j<=tot;j++)if(c[j]) if(((i&j)==0)&&(((j>>1)&i)==0)&&(((i>>1)&j)==0)) c2[i][j]=1; } int main(){ cin>>n>>k;tot=(1<<n)-1;df(); for(int i=0;i<=tot;i++)if(c[i])dp[1][cnt[i]][i]=1; for(int i=1;i<n;i++) for(int j=0;j<=tot;j++)if(c[j]) for(int l=0;l<=tot;l++)if(c[l]) if(c2[j][l]) for(int p=0;p<=k;p++) dp[i+1][cnt[l]+p][l]+=dp[i][p][j]; for(int i=0;i<=tot;i++)ans+=dp[n][k][i]; cout<<ans; return 0; }
1084(s_a_b_e_r)

by:s_a_b_e_r


以上是非常正經的s_a_b_e_r的題解
以下是非常不正經的wypx的題解

……

不過感覺他說的挺詳細了就沒我什麽事了吧╮(╯▽╰)╭

做的時候沒用什麽c1[i]啊c2[i][j]啊什麽的,感覺好麻煩x

在dp之前先dfs一遍

把所有可能的狀態都壓進一個vector裏

然後dp的時候就不用枚舉所有狀態了,直接從vector裏往外拿

f[i][j][x]表示處理到第i行,放了j個棋子,現在的狀態編號是x

(其實他不用vector是因為他不會用x)

技術分享
#include<iostream>
#include<cstdio>
#include<vector>

using namespace std;
const int N=200;
int n,k,num[N];
bool d[10];
long long f[N][N][N];
vector<int>a;
void dfs(int x) 
{
    if(x>n)
    {
      int ans=0;
      for(int i=1;i<=n;++i)
      {
        ans<<=1;
        if(d[i]){++ans;++num[a.size()];}
      }
      a.push_back(ans);
      return;
    }
    dfs(x+1);
    if(!d[x-1])
    {
      d[x]=1;
      dfs(x+1);
      d[x]=0;
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    dfs(1);
    int tot=a.size();
    for(int i=0;i<tot;++i)
      f[1][num[i]][i]=1;
    for(int i=1;i<n;++i)
    for(int x=0;x<tot;++x)
    for(int y=0;y<tot;++y)
      if( ((a[x]&a[y])==0) && (((a[x]<<1)&a[y])==0) && ((a[x]&(a[y]<<1))==0) )
        for(int j=num[x];j+num[y]<=k;++j)
          f[i+1][j+num[y]][y]+=f[i][j][x];
    long long ans=0;
    for(int i=0;i<tot;++i)ans+=f[n][k][i];
    cout<<ans<<endl;
    return 0;
}
1084(wypx)

by:wypx


s:今天的天空璋好花啊,音樂棒棒的x

w:快去做題>_<

bzoj 1087 [SCOI2005] 互不侵犯King