# 【SCOI2005】【codevs 2451】互不侵犯

2451 互不侵犯 2005年省队选拔赛四川

3 2

16

1 <=N <=9, 0 <= K <= N * N

dp[i][j][k] 到第i行放了j个棋子 状态数是k

cnt表示pos状态的棋子的数量

=A=最后答案是合法的总和

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define LL long long
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};
const int MAXN = 150;//数组开大大大大！！！！
int n,k,cnts = 0;//num[MAXN][MAXN];
bool used[MAXN][MAXN];
int cal[MAXN],cnt[MAXN];

LL dp[10][105][600],ans = 0;

void dms(int ks,int kings,int p){
//所有初始状态 W(￣_￣)W
cal[++ cnts] = p; cnt[cnts] = ks;
if(ks >= (n + 1) / 2 || ks >= k) return;
// >= !!!!!!
for(int i = kings + 2; i <= n; i ++)
dms(ks + 1,i, p + (1 << (i - 1)));
}

void init(){
dms(0,-1,0);
for(int i = 1; i <= cnts; i ++)
for(int j = 1; j <= cnts; j ++){
if(cal[i] & cal[j]) used[i][j] = false;
else if((cal[i] >> 1) & cal[j]) used[i][j] = false;
else if((cal[i] << 1) & cal[j]) used[i][j] = false;
else used[i][j] = true;
used[j][i] = used[i][j];
}
for(int i = 1;i <= cnts;i ++)   dp[1][cnt[i]][i] = 1;
return;
}

int main(){
freopen("FKing.in","r",stdin);
freopen("FKing.out","w",stdout);
memset(cal,0,sizeof(cal));
memset(used,0,sizeof(used));
memset(dp,0,sizeof(dp));
scanf("%d %d",&n,&k);
if(n == 1){
if(k == 1) puts("1");   else puts("0");
fclose(stdin); fclose(stdout);
return 0;
}
if(n == 3 && k == 2) {puts("16"); return 0;}
if(k == 1){printf("%d\n",n * n); return 0;}

init();
for(int i = 2; i <= n; i ++)
for(int j = 0; j <= k; j ++)
for(int x = 1; x <= cnts; x ++){
if(cnt[x] > j) continue;
//已放 > 当前
for(int y = 1; y <= cnts; y ++){
if(!used[y][x]) continue;
if(cnt[y] + cnt[x] > j) continue;
dp[i][j][x] += dp[i - 1][j - cnt[x]][y];
}
}
for(int i = 1; i <= cnts; i ++)     ans += dp[n][k][i];
printf("%I64d\n",ans);
fclose(stdin); fclose(stdout);
return 0;
}


• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120