题目描述
在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入
对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击
输入格式
第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数。接下来的 m 行给出障碍的位置。每行 2 个正整数,表示障碍的方格坐标。
输出格式
将计算出的共存骑士数输出
输入输出样例
输入
3 2 1 1 3 3
输出:
5
思路:本题显然不存在唯一一行对应唯一一列(車的放置)的关系,那么我们将每个“日”字的对角线进行连接 表示这两个端点无法共存。原题转化为:如何去掉最少的点,去掉所有的边
等效于点数-最小点覆盖。那么引出:最大独立集=n-最小点覆盖
类似于【Asteroids POJ - 3041 【最小点覆盖集】】的思想。先求出除了障碍物以外每一个点所能到达的点【到达的点不能是障碍物】。然后在两个相互能到达的点集中 求最小点覆盖{即删掉最小的点使得删掉所有的边【套模板】 }(求出的答案 注意 ans/2 因为是相互的)。然后再套公式:最大独立集=n-最小点覆盖即可。
AC代码:
1 #include<bits/stdc++.h> 2 3 //最大独立集=n-最小点覆盖 4 using namespace std; 5 #define maxn 666 6 int dx[]={1,1,2,2,-1,-1,-2,-2}; 7 int dy[]={2,-2,1,-1,2,-2,1,-1}; 8 int mp[maxn][maxn]; 9 int match[666*666]; 10 int vis[666*666]; 11 vector<int> v[666*666*3]; 12 int num[maxn][maxn]; 13 int flag=0; 14 int n,m; 15 int head[maxn*maxn]; 16 inline int read(){ 17 char c = getchar(); int x = 0, f = 1; 18 while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} 19 while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar(); 20 return x * f; 21 } 22 struct Edge{ 23 int to,next; 24 }e[666*666*4]; 25 void add(int u,int v){ 26 flag++; 27 e[flag].to=v; 28 e[flag].next=head[u]; 29 head[u]=flag; 30 } 31 int dfs(int u){ 32 for(int i=head[u];i;i=e[i].next){ 33 int temp=e[i].to; 34 if(!vis[temp]){ 35 vis[temp]=1; 36 if(match[temp]==0||dfs(match[temp])) 37 { 38 match[temp]=u; 39 return 1; 40 } 41 } 42 } 43 return 0; 44 } 45 void ok(int x,int y){ 46 for(int i=0;i<8;i++){ 47 int tx=x+dx[i]; 48 int ty=y+dy[i]; 49 if(tx>0&&ty>0&&tx<=n&&ty<=n&&!mp[tx][ty]){ 50 //v[num[x][y]].push_back(num[tx][ty]); 51 //v[num[tx][ty]].push_back(num[x][y]); 52 add(num[x][y],num[tx][ty]); 53 add(num[tx][ty],num[x][y]); 54 } 55 } 56 } 57 int main(){ 58 //int n,m; 59 //scanf("%d%d",&n,&m); 60 n=read(); 61 m=read(); 62 for(int i=1;i<=m;i++){ 63 int x,y; 64 //scanf("%d%d",&x,&y); 65 x=read();y=read(); 66 mp[x][y]=1;// 标记不可以走到的点 67 } 68 int cnt=0; 69 for(int i=1;i<=n;i++) 70 for(int j=1;j<=n;j++) 71 num[i][j]=++cnt; // 给每一个点编号 72 for(int i=1;i<=n;i++){ 73 for(int j=1;j<=n;j++){ 74 if(mp[i][j]) 75 continue; 76 else{ 77 ok(i,j); 78 } 79 } 80 } 81 //memset(match,0,sizeof(match)); 82 int ans=0; 83 for(int i=1;i<=cnt;i++){ 84 // memset(vis,0,sizeof(vis)); 85 for(int i=0;i<=cnt;i++) 86 vis[i]=0; 87 if(dfs(i)) 88 ans++; 89 } 90 int res=n*n-m-ans/2; 91 printf("%d ",res); 92 return 0; 93 }