Acdream 1132 Chess(状压dp)

Chess

Time Limit: 2000/1000MS (Java/Others)  Memory Limit: 128000/64000KB (Java/Others)
Problem Description

Xiang-qi is a kind of traditional Chinese chess. There is a special role in the game called “Jiang” (or called “Shuai”). When you want to operate this kind of role, it can only dominating the four neighbor cell and can of course attack the role there (In fact there is a special condition can allow the role attack farther distance but we ignore this condition).

Now we have an N*N chessboard, we want to place some “Jiang” on it. Of course we have several restraints on placing chess pieces:

1. The placing chess role cannot dominate each other.
2. On the chessboard all cells without placing chess should be dominated.
3. There are some cells called “Hole” which cannot be placed by chess piece. Attention that the hole should also be dominated.

For a given chessboard, we want to know the least number of chess pieces to place which can satisfy the restraints above.

Input

There are multiple test cases.

In each test case, the first line contains two integers N and K indicating the size of the chessboard and the number of the holes on the chessboard. (1 <= N <= 9, 0 <= K <= N*N)

In the next K line each line contains two integers x and y indicating the cell (x, y) is a hole cell. (1 <= x, y <= N)

You can get more details from the sample and hint.

Output

For each test case, you should output an integer indicating the answer of the test case. If there is no way to place the chess pieces, please output -1.

Sample Input
3 2
1 1
3 3
Sample Output
3
Hint

In the sample we can have several ways to placing the chess pieces:

Place on (1, 3), (2, 1) and (3, 2);
Place on (3, 1), (1, 2) and (2, 3);

Although place on (1, 2), (2, 2) and (3, 2) can dominate all cell but it is not satisfy the first restraint. And place on (1, 1), (1, 3) and (3, 2) is also illegal because the cell (1, 1) is a hole.


题目链接:http://acdream.info/problem?pid=1132



//dp[i][cur][up] 代表 i行 type[cur]状态,i-1行是type[up]时放的棋子数目

//思路:先预处理哪一些状态没有相邻的1, 状态中1代表放了  将  ,
//因为放第i行时当前状态不能喝hole冲突,且不能喝i-1行状态冲突,且必须使得i-1行中的格子都要被控制,
//而i-1行被控制的状态与i-2也有关,所以也要记录i-2行的状态,所以用3维dp

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>


#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)

#define eps 1e-8
//typedef __int64 ll;

#define fre(i,a,b)  for(i = a; i < b; i++)
#define frer(i,a,b) for(i = a; i > =b;i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define ssf(n)      scanf("%s", n)
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define bug         pf("Hi\n")

using namespace std;

#define INF 0x3f3f3f3f
#define N 520

int dp[10][N][N];
int type[N],k;
int n,m,h[10],num[N];

int lowbit(int x)     //计算x状态1的数目
{
	int t=0;
	while(x)
	{
		t++;
		x&=(x-1);
	}
   return t;
}

bool ok(int x)
{
	if(x&(x<<1)) return false;
	return true;
}

void inint()       //预处理每一行没有相邻的11状态
{
	int i,j;
	int len=1<<n;
	k=0;
	fre(i,0,len)
	 if(ok(i))
		type[k++]=i;

	fre(i,0,k)
	  num[i]=lowbit(type[i]);    //求出这一种状态的1的数目
}

void solve()
{
     int i,j,cur,up,uup;
     fre(i,2,n)
       fre(cur,0,k)      //当前状态
       {
       	   if(type[cur]&h[i]) continue;

       	   fre(up,0,k)         //上一行状态
       	   {
       	   	  if(type[up]&h[i-1]) continue;
       	   	  if(type[up]&type[cur]) continue;

       	   	  fre(uup,0,k)       //上上一行状态
       	   	  {
       	   	      if(type[uup]&h[i-2]) continue;
       	   	      if(type[uup]&type[up]) continue;
                  if(!dp[i-1][up][uup]) continue;
       	   	      int t=type[up]|(type[up]<<1)|(type[up]>>1);
       	   	      t|=type[uup];
       	   	      t|=type[cur];
       	   	      t&=(1<<n)-1;    //这一步很重要,bug半天
       	   	      if(t!=(1<<n)-1) continue;
       	   	      dp[i][cur][up]=min(dp[i][cur][up],dp[i-1][up][uup]+num[cur]);
       	   	  }
       	   }
       }
	int ans=INF;

	fre(i,0,k)
	 fre(up,0,k)
	 {
	 	if(dp[n][i][up]==INF)  continue;
	 	if(h[n]&type[i]) continue;
	 	if(h[n-1]&type[up]) continue;
	 	if(type[i]&type[k]) continue;
	 	int t=type[i]|(type[i]<<1)|(type[i]>>1);
	 	t|=type[up];
	 	t&=(1<<n)-1;
	 	if(t!=(1<<n)-1) continue;
	 	if(!dp[n][i][up]) continue;
	 	ans=min(ans,dp[n][i][up]);
	 }
     if(ans==INF) ans=-1;
     printf("%d\n",ans);
}

int main()
{
    int i,j;
    while(~sff(n,m))
	{
       inint();
       mem(h,0);
       int x,y;
       while(m--)
	   {
	   	  sff(x,y);
	   	  h[x]|=1<<(y-1);
	   }

       mem(dp,0);

       fre(i,0,k)
         {
         	if(type[i]&h[1]) continue;
         	dp[1][i][0]=num[i];
         }
	solve();
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值