POJ 1321--棋盘问题

32 篇文章 0 订阅
29 篇文章 0 订阅
  •   DFS:16ms.首先枚举从n行中选择cheeseNum个行的个数,也就是选择棋子的过程中第一行必须是[0,n-cheeseNum]之间,DFS过程中第二行的开始行数就必须在第一个棋子基 础上加1,同时能有棋子分布的第二行的最大行数加1。当棋子的最大可能行数为n时,即DFS了cheeseNum层,并且列数无冲突时,结果加一。

  •   状态压缩DP:0ms。
  1. setNum[i][j]:第i行时对应状态j能部署的棋子的方案数。状态j对应的方案:其二进制相应位数对应列数,为1则放棋子,为0不放。
  2. 可以得到转移方程:显然基底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].
  3. 注意setNum[0][0]初始化为1,即第0行不布置棋子有1种方案,这样才能向下迭代。
  4. 算法中通过行数迭代,当前行状态只能由上层状态转换而来,达到每行选一个的目的,而每列选一个则有状态和新状态的条件式控制。

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;
}

DP:
#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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值