- DFS:16ms.首先枚举从n行中选择cheeseNum个行的个数,也就是选择棋子的过程中第一行必须是[0,n-cheeseNum]之间,DFS过程中第二行的开始行数就必须在第一个棋子基 础上加1,同时能有棋子分布的第二行的最大行数加1。当棋子的最大可能行数为n时,即DFS了cheeseNum层,并且列数无冲突时,结果加一。
- 状态压缩DP:0ms。
- setNum[i][j]:第i行时对应状态j能部署的棋子的方案数。状态j对应的方案:其二进制相应位数对应列数,为1则放棋子,为0不放。
- 可以得到转移方程:显然基底setNum[i][j] += setNum[i-1][j],并且当棋盘在i行k列有棋子,并且状态j中第k位为0,则可以知道加入此棋子满足题意,新状态new_state = j|(1<<(k-1)),且:setNum[i][new_state] += setNum[i-1][j].
- 注意setNum[0][0]初始化为1,即第0行不布置棋子有1种方案,这样才能向下迭代。
- 算法中通过行数迭代,当前行状态只能由上层状态转换而来,达到每行选一个的目的,而每列选一个则有状态和新状态的条件式控制。
DFS:
#include<cstdio>
#include<cstring>
using namespace std;
#define maxN 9
char adj[maxN][maxN];
char adjNum[maxN];
short n,cheeseNum;
int setNum;
char DFS(char maxRowNo,char rowNo,char visColumn)
{
if(maxRowNo == n)
{
setNum++;
return 0;
}
short i,j;
char column;
for(i = rowNo;i <= maxRowNo;i++)
for(j = 0;j < adjNum[i];j++)
{
column = adj[i][j];
if(!(visColumn&(1<<column)))
{
DFS(maxRowNo+1,i+1,visColumn^(1<<column));
}
}
return 0;
}
int main()
{
short i,j;
char tmp[maxN];
while(scanf("%hd%hd",&n,&cheeseNum))
{
if(n == -1&&cheeseNum == -1)
return 0;
setNum = 0;
memset(adjNum,0,sizeof(adjNum));
getchar();
for(i = 0;i < n;i++)
{
gets(tmp);
for(j = 0;j < n;j++)
{
if(tmp[j] == '#')
{
adj[i][adjNum[i]++] = j;
}
}
}
DFS(n-cheeseNum,0,0); //n-cheeseNum为方案中第一个棋子能放置的最大行数,0为其当前行数
printf("%d\n",setNum);
}
return 0;
}
#include<cstdio>
#include<cstring>
using namespace std;
#define maxN 10
#define stateN 256
int main()
{
char cheeseBoard[maxN][maxN];
short n,cheeseNum,stateNum;
int setNum[maxN][stateN];
short State2Num[stateN];
short i,j,k;
int ans;
/***状态转换成列数****/
for(i = 0;i < stateN;i++)
{
k = 0;
for(j = 0;j < 8;j++)
{
if(i&(1<<j))
k++;
}
State2Num[i] = k;
}
while(scanf("%hd%hd",&n,&cheeseNum))
{
if(n == -1&&cheeseNum == -1)
return 0;
memset(setNum,0,sizeof(setNum));
setNum[0][0] = 1;
stateNum = 1<<n;
ans = 0;
getchar();
for(i = 1;i <= n;i++)
gets(cheeseBoard[i]+1);
for(i = 1;i <= n;i++)
for(j = 0;j < stateNum;j++)
if(State2Num[j] <= cheeseNum)
{
setNum[i][j] += setNum[i-1][j];
for(k = 1;k <= n;k++)
if(cheeseBoard[i][k] == '#'&&(j&1<<(k-1)) == 0) //i行k列能放棋子,并且状态j的k列没有棋子
setNum[i][j|(1<<(k-1))] += setNum[i-1][j];
}
for(i = 0;i < stateNum;i++)
if(State2Num[i] == cheeseNum)
ans += setNum[n][i];
printf("%d\n",ans);
}
return 0;
}