vijos p1729 Knights

描述

在一个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行,每行一个字符串,描述一个骑士的坐标。

输出格式

输出一行,一个整数,表示至少拿走多少个骑士。

样例1

样例输入1[复制]

 
6 9
A1
A5
B3
C5
C1
D2
D4
E6
F5

样例输出1[复制]

 
3

限制

每个测试点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 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值