https://turingjudge.com/contest/3/problem/1002
QkCvNnnjg5
题意:
在一个棋盘上给出一些马,问最少删掉几个使得两两不能吃。
解析:
如果是一对一冲突,输出方案是2SAT问题。
如果是一对多输出,输出最大数量,是最大独立集问题。
最少删掉几个就是最多留下几个,也就是最大独立集。
将冲突的马之间匹配上,求一个最大独立集(n-最大匹配)。
由于不是二分图,可以左边n个,右边n个,最后除2即可。
代码:
/*
* Author : Jk_Chen
* Date : 2020-04-20-09.52.15
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
const int N=909;
int match[N];
bool vis[N];
bool link[N][N];
int n,m;
int fin(int h){
for(int i=1;i<=m;i++){
if(vis[i]||!link[h][i])continue;
vis[i]=1;
if(match[i]==0||fin(match[i])){
match[i]=h;return 1;
}
}
return 0;
}
int X[900],Y[900];
int have[30][30];
int di[8][2]={1,2,-1,2,1,-2,-1,-2, 2,1,-2,1,2,-1,-2,-1};
int main(){
n=rd,m=rd;
rep(id,1,m){
char x[4];
scanf("%s",x);
int i=x[0]-'A'+1;
int j=x[1]-'0';
if(strlen(x)==3){
j=j*10+x[2]-'0';
}
have[i][j]=id;
X[id]=i;
Y[id]=j;
}
rep(i,1,m){
rep(j,0,7){
int x=X[i]+di[j][0];
int y=Y[i]+di[j][1];
if(x<1||x>n||y<1||y>n||!have[x][y])continue;
link[i][have[x][y]]=1;
link[have[x][y]][i]=1;
}
}
int ans=0;
rep(i,1,m){
mmm(vis,0);
if(fin(i))ans++;
}
printf("%d\n",ans/2);
}