题目传送门
题目大意:一个矩阵,一些点被拿掉,在棋盘上马走日,马之间不能落在同一点,求最多放几匹马。
采用对矩阵黑白染色,画个图可以发现:马可以走到的位置和他所处的位置颜色不同,将马和他可以走到的位置连边,最多可以放多少马,相当于求图的最大独立集(任意一条边的两个端点不会同时被选中)。
用黑白染色将节点按颜色分成两类,就是一个二分图。
题解代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 40000
struct edge{
int to,nxt;
}e[maxn*8+5];
bool vis[maxn+5];
char Map[maxn+5][maxn+5];//存矩阵
int head[maxn+5]={0},link[maxn+5];
int dx[9]={-1,1,-2,2,-1,1,-2,2};
int dy[9]={-2,-2,-1,-1,2,2,1,1};//马走日的八个方位
int n,p,ans,cnt;
void add(int x,int y){//用矩阵中方格的编号建图
e[++cnt].nxt=head[x];
head[x]=cnt;
e[cnt].to=y;
}
int Getnum(int x,int y){//得到该点编号,相当于一个矩阵从左上依次数
return (x-1)*n+y;
}
void read(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
cin>>Map[i][j];
if(Map[i][j]=='1') p++;//统计障碍数
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(Map[i][j]=='0'&&(i+j)%2)//用黑白染色,左上是黑,(i+j)%2表示白色
for(int k=0;k<8;k++){//八个方位遍历
int tx=i+dx[k];
int ty=j+dy[k];
if(tx>=1&&tx<=n&&ty>=1&&ty<=n&&Map[tx][ty]=='0'){//满足条件
add(Getnum(i,j),Getnum(tx,ty));
}
}
}
bool match(int x){//标准的匈牙利算法
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(!vis[v]){
vis[v]=1;
if(!link[v]||match(link[v])){
link[v]=x;
return true;
}
}
}
return false;
}
void solve(){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(Map[i][j]=='0'&&(i+j)%2){
memset(vis,0,sizeof(vis));
if(match(Getnum(i,j))) ans++;
}
cout<<n*n-p-ans;//最大独立集=节点总数减去最大匹配
}
int main(){
read();
solve();
return 0;
}
自己写的垃圾代码:
#include<bits/stdc++.h>
using namespace std;
const int N=40005;
struct edge{
int to,nxt;
}e[N<<3];
int n,p,tot,ans,head[N];
char Map[N][N];
bool vis[N];
int link[N],dx[8]={-1,-2,-2,-1,1,2,2,1},dy[8]={-2,-1,1,2,2,1,-1,-2};
int Gm(int x,int y){
return (x-1)*n+y;
}
void add(int x,int y){
e[++tot].nxt=head[x];
head[x]=tot;
e[tot].to=y;
}
bool match(int x){
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(!vis[v]){
vis[v]=1;
if(!link[v]||match(link[v])){
link[v]=x;
return true;
}
}
}
return false;
}
void solve(){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(Map[i][j]=='0'&&(i+j)%2){
memset(vis,0,sizeof(vis));
if(match(Gm(i,j))) ans++;
}
return ;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
cin>>Map[i][j];
if(Map[i][j]=='1') p++;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(Map[i][j]=='0'&&(i+j)%2){
for(int k=0;k<8;k++){
int tx=i+dx[k],ty=j+dy[k];
if(tx>=1&&tx<=n&&ty>=1&&ty<=n&&Map[tx][ty]=='0')
add(Gm(i,j),Gm(tx,ty));
}
}
solve();
cout<<n*n-p-ans;
}