0
点赞
收藏
分享

微信扫一扫

洛谷P4304 TJOI2013 攻击装置

司马吹风 2022-03-19 阅读 20
图论

题目传送门

题目大意:一个矩阵,一些点被拿掉,在棋盘上马走日,马之间不能落在同一点,求最多放几匹马。

采用对矩阵黑白染色,画个图可以发现:马可以走到的位置和他所处的位置颜色不同,将马和他可以走到的位置连边,最多可以放多少马,相当于求图的最大独立集(任意一条边的两个端点不会同时被选中)。

用黑白染色将节点按颜色分成两类,就是一个二分图。

题解代码:

#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;
}
举报

相关推荐

0 条评论