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 }

时间: 2024-10-11 20:02:39

vijos p1729 Knights的相关文章

【vijos】1729 Knights(匈牙利)

https://vijos.org/p/1729 这题好奇葩,为嘛N开到30就会re啊..........n<=26吗.... sad 因为根据棋子的分布,能攻击的一定各在一黑白格上,所以直接二分图了. (但是我想了想,如果不是黑白格的,怎么做............................ #include <cstdio> #include <cstring> #include <cmath> #include <string> #incl

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

Vijos P1785 同学排序【模拟】

同学排序 描述 现有m位同学,第1位同学为1号,第2位同学为2号,依次第m位同学为m号.要求双号的学生站出来,然后余下的重新组合,组合完后,再次让双号的学生站出来,重复n次,问这时有多少同学出来站着? 样例1 样例输入1 1989 5 样例输出1 1926 限制 1s 提示 [数据范围] 1≤n≤10 100≤m≤100000 题目链接:https://vijos.org/p/1785 分析:站出序号为偶数的人,如果总人数为奇数,剩余人数向上取整再折半就好了! 下面给出AC代码: 1 #incl

Vijos 1057 盖房子

二次联通门 : Vijos 1057 盖房子 /* Vijos 1057 盖房子 简单的dp 当前点(i, j)所能构成的最大的正方形的边长 为点(i - 1, j - 1)与(i, j - 1), (i - 1, j)三点中最小的边长构成.. 一遍递推, 一边取最大即可 */ #include <cstdio> #define Max 1009 inline int min (int a, int b) { return a < b ? a : b; } inline int max

Vijos 1193 扫雷 【动态规划】

扫雷 描述 相信大家都玩过扫雷的游戏.那是在一个n*n的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了,"余"任过流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子没有雷,那么它里面的数字表示和他8连通的格子里面雷的数目.现在棋盘是n*2的,第一列里某些格子是雷,而第二列没有雷,如:o 1* 2* 3* 2o 2* 2* 2 ('*'代表有雷,'o'代表无雷)由于第一类的雷有可能有多种方案满足第二列的数的限制,你的任务即根据第二列的信息求第一列雷有多少中摆放方案.

Vijos 1523 贪吃的九头龙 【树形DP】

贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted by JackDavid127 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,

vijos P1448 校门外的树

描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作接下来m行为m个操作 输出格式 对于每个k=2输出一个答案 提示 范围:20%的数据保证,n,m<=10060%的数据保证

Light OJ 1315 - Game of Hyper Knights

传送门 1315 - Game of Hyper Knights    PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 32 MB A Hyper Knight is like a chess knight except it has some special moves that a regular knight cannot do. Alice and Bob are playing this game

Vijos P1061 迎春舞会之三人组舞 DP

题目链接:https://vijos.org/p/1061 n个人选出3*m人,排成m组,每组3人. 站的队形——较矮的2个人站两侧,最高的站中间. 从对称学角度来欣赏,左右两个人的身高越接近,则这一组的“残疾程度”越低. 计算公式为 h=(a-b)^2 (a.b为较矮的2人的身高)现在候选人有n个人,要从他们当中选出3*m个人排舞蹈,要求总体的“残疾程度”最低; input: 第一排为m,n. 第二排n个数字,保证升序排列. 思路:由于和中间高的人无关,但是每次选旁边两个的时候,会由于没有比这