Chess
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.
Source
Manager
状态压缩DP,许久没有碰状态压缩DP,这次一作果然生疏不少,这题一看到一想蛮简单的上一层可以直接转移状态到下一层,结果没有考虑周全,胡乱WA了两次都不知道错在哪,静下心来仔细分析后才发现并不是可以直接推的,我少考虑了一个状态,比如0010是可以推到1000的,因为我开始做的时候除了两边的层之外要保证前一层满占据,1000虽然没有保证0010满占据,但其实更上一层的情况是可以左右0010的占据情况的,本以为这样三层DP会不会TLE,但再次分析之后发现许多情况重复,可以先预处理加判断少好几层的DP,所以是可行的,但是枚举的不是三层的情况,而是上一层和这一层和上上一层对上一层的加成可能情况(真是别扭~~)
看代码知道更多
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#define rep(i,n) for(i=1;i<=n;i++)
#define MM(a,t) memset(a,t,sizeof(a))
#define INF 1e9
typedef long long ll;
#define mod 1000000007
using namespace std;
int n,m;
int ken[11][11];
int dp1[11][514][514];
int ptwo[10],sum[514],ko[514];
int hefa[514],fhefa[11][514];
int jicot(int num){int i,j,res=0;while(num>0){res+=num&1;num>>=1; }return res;
}
int jiko(int num){int i,j,res=0;int wei[11];MM(wei,0);i=n;while(i>0){if((num&1)==1){wei[i]=1; wei[i+1]=1; wei[i-1]=1;}num>>=1;i--;if(num==0) break;}for(i=n;i>=1;i--){if(wei[i]==1) res+=ptwo[n-i];}return res;
}
bool check(int num,int ii){int i=n,j;while(i>0){if(ken[ii][i]==1 && (num&1)==1) return false;i--;num>>=1;if(num==0) return true;}return true;
}
void dpmain(){int i,pr,now,prr;for(now=0;now<ptwo[n];now++)if(fhefa[1][now]) { dp1[1][now][ko[now]]=sum[now]; }for(i=2;i<=n;i++)for(pr=0;pr<ptwo[n];pr++)if(fhefa[i-1][pr])for(now=0;now<ptwo[n];now++)if((pr & now)==0 && fhefa[i][now]){if(i==n && (ko[now]|pr)!=ptwo[n]-1) continue; for(prr=pr;prr<ptwo[n];prr++) {if(dp1[i-1][pr][prr]==-1 || (now|prr)!=ptwo[n]-1) continue; dp1[i][now][ko[now]|pr]=(dp1[i][now][ko[now]|pr]==-1)?dp1[i-1][pr][prr]+sum[now]:min(dp1[i][now][ko[now]|pr],dp1[i-1][pr][prr]+sum[now]); } } }
int jihefa(int num){int i=9,j;while(i>0){if((num&2)==2 && (num&1)==1) return 0;i--;num>>=1;if(num==0) return 1;}return 1;
}
void setup(){int i,j;ptwo[0]=1;rep(i,9){ptwo[i]=ptwo[i-1]*2;}for(i=0;i<ptwo[9];i++){ sum[i]=jicot(i);hefa[i]=jihefa(i);}
}
int main()
{int i,j;setup();while(scanf("%d%d",&n,&m)!=EOF){MM(ken,0); MM(dp1,-1);rep(i,m){int x,y;scanf("%d%d",&x,&y);ken[x][y]=1;}for(i=0;i<ptwo[n];i++)ko[i]=jiko(i);MM(fhefa,0);rep(i,n)for(j=0;j<ptwo[n];j++)if(hefa[j] && check(j,i)) fhefa[i][j]=1;if(n==1){if(ken[1][1]==1) printf("-1\n");else printf("1\n");continue;}dpmain();int res=1000;for(i=0;i<ptwo[n];i++)if(dp1[n][i][ptwo[n]-1]!=-1){res=min(res,dp1[n][i][ptwo[n]-1]);}if(res==1000) printf("-1\n"); else printf("%d\n",res);}return 0;
}