直接質問に騒ぎ、:
1592:王[例1]
制限時間:500ミリ秒のメモリ制限:65536キロバイト
で番号290:111番号を提出
説明[タイトル]
SGU 223:オリジナルタイトルから
では 、n個のチェス盤×n個の場所 のk-キング、隣接攻撃することができます 合計8つの格子を、彼らはそれぞれのプログラムを攻撃することはできませんがわかります。
[Enter]を
二つの整数を含む唯一の行、 n及び kは。
[出力]
行動プログラムの各データの合計数は、もし出力を配置することができる 0。
[サンプル入力]
3 2
[サンプル出力]
16
[注]
サンプル入力2
4 4
サンプル出力2
79
データ範囲とヒント:
すべてのデータについては、1≤n≤10,0≤k≤n 2 。
[ソース]
この質問にはまだn個の女王のような多すぎる、と言っています。この質問のリンクを参照してください:ああ、ここで突く〜
しかし、女王は王だけでなく、マップ上のピットになります。
しかし、我々はまず、データの大きさで、私はに怖がっていた突然のすべてを見ることができます。nは、それらを検索する検索本当にわずか10、kは唯一の100ですが、データは少ないが、しかし、それは本当に確かに、指数関数的に複雑ではないかもしれません。
だから我々はこの質問には、小さなシリーズで、実際に、それはバイナリ最適化の使用を意味し、ずっと前に使用されている、状態の圧縮動的なプログラミングクラスに属し、最適化を選択する必要があります。
我々はすべて知っているように、それはこのバイナリです:1010110、0と1の束が、あなたのマップが1と0で構成されている場合、それは、最適化を行うことができます。
このイラスト:
実際に記事を増加からダウンコピーします。
そして、行データは数に凝縮され、その後、我々だけを扱うにlowbit原理と1のx&-xの最高レベルを見つけることができます1(他の大物は非常に明確ではありませんなぜ、私に聞かないでください)。
好了,回归正题,这道题是动态规划题,那么怎样设计状态呢?
我们要在n*n的棋盘上放k个国王,那么我们不妨用f[i][j][k]来表示第i行的状态是a[j](二进制表示),目前为止放了k个棋子。
显然f[i][j][k]=sum{i-1,l,k-num[j]}(不发生冲突),其中l是,枚举上一行状态的变量,num[j]是a[j]这一状态可以放置的国王数。
行了,其他的都看注释吧,要不然不好解释,代码如下:
1 #include<iostream> 2 using namespace std; 3 long long n,K,num[1000],a[1000],sum,ans,f[300][300][300]; 4 void pre() 5 { 6 int cnt=0;//记录方案数 7 for(int i=0;i<(1<<n);i++)//注意,这里模拟的是一行的所有状态,而不是行数 8 { 9 if(i&(i<<1)) continue;//如果结果不是0,那么就会有1是挨着的,不合法 10 cnt=0; 11 for(int j=0;j<n;j++) if((1<<j)&i) cnt++;//如果i的二进制表示下的j位有1,那么就记录 12 a[++sum]=i;//记录状态 13 num[sum]=cnt;//记录可以放国王的数量 14 } 15 } 16 void dp() 17 { 18 f[0][1][0]=1;//显然第0行第一位上可以放一个国王 19 for(int i=1;i<=n;i++) 20 for(int j=1;j<=sum;j++) 21 for(int k=0;k<=K;k++) 22 { 23 if(k>=num[j])//先看能不能减 24 for(int l=1;l<=sum;l++) 25 if(!(a[l]&a[j]) && !(a[l]&(a[j]<<1)) && !(a[l]&(a[j]>>1)))//看看国王和上一行的国王起不起冲突 26 f[i][j][k]+=f[i-1][l][k-num[j]]; 27 } 28 for(int i=1;i<=sum;i++) ans+=f[n][i][K];//最后一行的所有状态都要加上 29 cout<<ans; 30 } 31 int main() 32 { 33 cin>>n>>K; 34 pre();dp(); 35 return 0; 36 }