描述
在一个N*N的正方形棋盘上,放置了一些骑士。我们将棋盘的行用1开始的N个自然数标记,将列用'A'开始的N个大写英文字母标记。举个例子来说,一个标准的8*8的国际象棋棋盘的行标记为1..8,列标记为A..H,D3、H1分别表示棋盘上第3行第4列和第1行第8列的格子。
骑士是这样一类棋子。若一个骑士放置在格子(x, y)。那么格子(x-2, y-1), (x-2, y+1), (x-1, y-2), (x-1, y+2), (x+1, y-2), (x+1, y+2), (x+2, y-1), (x+2, y+1)如果在棋盘内的话,就都处于这个骑士的攻击范围内。
如果若干个骑士在棋盘上的一种放置方法能使得没有一个骑士处在其它骑士的攻击范围内,那么称为和谐的方案。现在给定一个棋盘,上面已经放置了M个骑士。你的任务是拿走尽可能少的骑士,使得剩余的骑士构成一个和谐的方案。
格式
输入格式
第一行,两个正整数N,M,分别表示棋盘的大小,和骑士的数目。
以下M行,每行一个字符串,描述一个骑士的坐标。
输出格式
输出一行,一个整数,表示至少拿走多少个骑士。
限制
每个测试点1s
提示
30%的数据满足,1 <= N <= 4.
100%的数据满足,1 <= N <= 26,骑士的坐标格式均合法,任意两个骑士的位置都不同。
来源
Topcoder
————————————我是分割线————————————————————
二分图问题。
看到这道题我们先会想到贪心,就是那个骑士被踩的最多,就先拿哪个。
但是,提交后就只过了5个点, 其实这种贪心策略是不对的
特殊情况
当图G是以最大度数为偶数的点对称的奇阶图时,这种策略就是不对的....
那么要怎么做呢..
我们可以将各个骑士看成点,然后将互相攻击的骑士连边,那么求拿走多少也就是求这个图最小点的覆盖
求一般图的最小点的覆盖时无法在多项式时间里解决的.....
那要怎么办呢
我们知道二分图的最大匹配就是最小点的覆盖,那我们看看这个图是不是二分图。
这个图就是二分图
证明:
将棋盘黑白二染色,即将A1染成黑色,然后与A1相邻的格子染成白色,然后与白色格子相邻的再染成黑色,依次类推。那么可以发现,两个发生冲突的骑士所在的格子一定是一黑一白。那么,将白色格子的骑士对应的点设为无向图的X部,黑色对应到Y部,那么边就只存在于两部分的点之间。得证。
所以将x部的点向y部的点连边,得到一张二分图,那么求这个二分图的最大匹配就是结果。
1 /* 2 Problem: 3 OJ: 4 User:S.B.S. 5 Time: 6 Memory: 7 Length: 8 */ 9 #include<iostream> 10 #include<cstdio> 11 #include<cstring> 12 #include<cmath> 13 #include<algorithm> 14 #include<queue> 15 #include<cstdlib> 16 #include<iomanip> 17 #include<cassert> 18 #include<climits> 19 #include<functional> 20 #include<bitset> 21 #include<vector> 22 #include<list> 23 #include<map> 24 #define maxn 100001 25 #define F(i,j,k) for(int i=j;i<=k;i++) 26 #define M(a,b) memset(a,b,sizeof(a)) 27 #define FF(i,j,k) for(int i=j;i>=k;i--) 28 #define inf 0x3f3f3f3f 29 #define maxm 1001 30 #define mod 998244353 31 //#define LOCAL 32 using namespace std; 33 int read(){ 34 int x=0,f=1;char ch=getchar(); 35 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 36 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 37 return x*f; 38 } 39 const int dx[]={-1,-2,-2,-1,1,2,2,1}; 40 const int dy[]={-2,-1,1,2,2,1,-1,-2}; 41 int n,m; 42 struct EDGE 43 { 44 int from; 45 int to; 46 int next; 47 }e[maxn]; 48 struct NODE 49 { 50 int x; 51 int y; 52 }a[maxn]; 53 int head[maxn]; 54 int tot; 55 int vis[maxm][maxm],ins[maxn]; 56 int py[maxn]; 57 int ans; 58 inline void addedge(int u,int v) 59 { 60 tot++; 61 e[tot].from=u; 62 e[tot].to=v; 63 e[tot].next=head[u]; 64 head[u]=tot; 65 } 66 inline bool path(int x) 67 { 68 int y; 69 for(int i=head[x];i;i=e[i].next) 70 { 71 if(!ins[y=e[i].to]){ 72 ins[y]=1; 73 if(!py[y]||path(py[y])){ 74 py[y]=x; 75 return true; 76 } 77 } 78 } 79 return false; 80 } 81 int main() 82 { 83 // std::ios::sync_with_stdio(false);//cout<<setiosflags(ios::fixed)<<setprecision(1)<<y; 84 #ifdef LOCAL 85 freopen("data.in","r",stdin); 86 freopen("data.out","w",stdout); 87 #endif 88 cin>>n>>m; 89 char s[10]; 90 F(i,1,m){ 91 gets(s+1); 92 a[i].x=s[1]-'A'+1; 93 int len=strlen(s+1); 94 F(j,2,len){ 95 a[i].y*=10; 96 a[i].y+=s[j]-'0'; 97 } 98 vis[a[i].x][a[i].y]=i; 99 } 100 F(i,1,m){ 101 F(k,0,7){ 102 int fx=dx[k]+a[i].x,fy=dy[k]+a[i].y; 103 if(fx<1||fy<1||fx>n||fy>n||!vis[fx][fy]) continue; 104 addedge(i,vis[fx][fy]); 105 } 106 } 107 F(i,1,m){ 108 if((a[i].x+a[i].y)&1){ 109 M(ins,0); 110 if(path(i)) ans++; 111 } 112 } 113 cout<<ans<<endl; 114 return 0; 115 }