Position:


Description

  从前有一个王国,这个王国的城堡是一个矩形,被分为M×N个方格。一些方格是墙,而另一些是空地。这个王国的国王在城堡里设了一些陷阱,每个陷阱占据一块空地。

   一天,国王决定在城堡里布置守卫,他希望安排尽量多的守卫。守卫们都是经过严格训练的,所以一旦他们发现同行或同列中有人的话,他们立即向那人射击。因此,国王希望能够合理地布置守卫,使他们互相之间不能看见,这样他们就不可能互相射击了。守卫们只能被布置在空地上,不能被布置在陷阱或墙上,且一块空地只能布置一个守卫。如果两个守卫在同一行或同一列,并且他们之间没有墙的话,他们就能互相看见。(守卫就像象棋里的车一样)

  你的任务是写一个程序,根据给定的城堡,计算最多可布置多少个守卫,并设计出布置的方案。

Input

第一行两个整数M和N(1≤M,N≤200),表示城堡的规模。

接下来M行N列的整数,描述的是城堡的地形。第i行j列的数用ai,j表示。

ai,j=0,表示方格[i,j]是一块空地;

ai,j=1,表示方格[i,j]是一个陷阱;

ai,j=2,表示方格[i,j]是墙。

Output

第一行一个整数K,表示最多可布置K个守卫。

此后K行,每行两个整数xi和yi,描述一个守卫的位置。

(若有多解,请输出字典序最小的那一种)

Sample Input

3 4

2 0 0 0

2 2 2 1

0 1 0 2

Sample Output

2

1 2

3 1

HINT

1≤M,N≤200

Search

这个题范围小一点跑暴力还是可以的,拿来练手,当搜索练习题很好,其中有很多优化,剪枝,可以拿到50分。

剪枝

  1. 记录当前搜索到的点(x,y),放了之后,预处理连续一段不能选的。见Code→lef数组
  2. 如果上面这列填了,那么就不填了。见Code→f数组。
  3. 并且要用down记录(x,y)选了,往下哪一段不能选。见Code→dow数组。
  4. 每扫过一行,看f数组要不要更新。见Code→b数组,并且当前要用d记录。
  5. 对于横着每一段,选择一个,那么搜索顺序呢?sort每个地方选了,下面有多少个不能选,从小到大搜,可以保证下面选的方案更多。见Code→c数组
  6. 没选完一个(x,y),记录之后有多少个空地还可以选。如果加上还小于当前ans,就可以return了。见Code→MA数组,记录(x,y)x这排y列之后有多少空地(0)。
  7. 搜索当然可以卡时啦。见if(clock()>CLOCKS_PER_SEC*0.963)pri();

Code

  1. // <guards.cpp> - Fri Sep 23 08:09:06 2016
  2. // This file is made by YJinpeng,created by XuYike's black technology automatically.
  3. // Copyright (C) 2016 ChangJun High School, Inc.
  4. // I don't know what this program is.
  5. #include <iostream>
  6. #include <vector>
  7. #include <algorithm>
  8. #include <cstring>
  9. #include <cstdio>
  10. #include <cstdlib>
  11. #include <cmath>
  12. #include <ctime>
  13. #define MOD 1000000007
  14. #define INF 1e9
  15. using namespace std;
  16. typedef long long LL;
  17. const int MAXN=210;
  18. const int MAXM=40010;
  19. inline int max(int &x,int &y) {return x>y?x:y;}
  20. inline int min(int &x,int &y) {return x<y?x:y;}
  21. inline int gi() {
  22. register int w=0,q=0;register char ch=getchar();
  23. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  24. if(ch=='-')q=1,ch=getchar();
  25. while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
  26. return q?-w:w;
  27. }
  28. int ans,n,m;bool f[MAXN];int b[MAXN];
  29. int a[MAXN][MAXN],lef[MAXN][MAXN],dow[MAXN][MAXN],MA[MAXN][MAXN];
  30. struct gg{int x,y;}g[MAXM],as[MAXM];
  31. struct node{
  32. int p,w;
  33. bool operator < (node a)const{return w<a.w;}
  34. };
  35. void pri(){
  36. printf("%d\n",ans);
  37. for(int i=1;i<=ans;i++)printf("%d %d\n",as[i].x,as[i].y);
  38. exit(0);
  39. }
  40. inline void work(register int x,register int y,register int nu){
  41. if(clock()>CLOCKS_PER_SEC*0.963)pri();
  42. if(x==n&&y>m){
  43. if(nu>ans){ans=nu;for(int i=1;i<=nu;i++)as[i]=g[i];}
  44. return;
  45. }
  46. if(y>m){
  47. int d[MAXN];
  48. for(int i=1;i<=m;i++){if(x==b[i])f[i]=0;d[i]=b[i];}
  49. work(x+1,1,nu);
  50. for(int i=1;i<=m;i++){b[i]=d[i];if(x==b[i])f[i]=1;}
  51. return;
  52. }
  53. int k=MA[x][y];
  54. for(int i=x+1;i<=n;i++)k+=MA[i][1];
  55. if(nu+k<=ans)return;
  56. int tot=0;node c[MAXN];
  57. for(int i=y;i<lef[x][y];i++){
  58. if(f[i]||a[x][i])continue;
  59. c[++tot]=(node){i,dow[x][i]};
  60. }
  61. if(!tot){work(x,lef[x][y]+1,nu);return;}
  62. sort(c+1,c+1+tot);
  63. for(int i=1;i<=tot;i++){
  64. f[c[i].p]=1,b[c[i].p]=x+c[i].w;
  65. g[nu+1]=(gg){x,c[i].p};
  66. work(x,lef[x][y]+1,nu+1);
  67. f[c[i].p]=(bool)(b[c[i].p]=0);
  68. }
  69. }
  70. int main()
  71. {
  72. freopen("guards.in","r",stdin);
  73. freopen("guards.out","w",stdout);
  74. n=gi(),m=gi();
  75. for(int i=1;i<=n;i++)
  76. for(int j=1;j<=m;j++)a[i][j]=gi();
  77. for(int i=1;i<=n;i++)lef[i][m+1]=m+1;
  78. for(int i=1;i<=n;i++)
  79. for(int j=m;j>=1;j--){
  80. if(a[i][j]==2){lef[i][j]=j;MA[i][j]=MA[i][j+1];continue;}
  81. lef[i][j]=lef[i][j+1];
  82. if(a[i][j]==1&&lef[i][j]==j+1){MA[i][j]=MA[i][j+1];continue;}
  83. MA[i][j]=MA[i][lef[i][j]+1]+1;
  84. }
  85. for(int i=1;i<=m;i++)
  86. for(int j=n;j>=1;j--){
  87. if(a[j][i]==2){dow[j][i]=0;continue;}
  88. dow[j][i]=dow[j+1][i]+1;
  89. }
  90. memset(f,false,sizeof(f));
  91. work(1,1,0);pri();
  92. return 0;
  93. }

Solution

这道题是二分图的经典模型。

最关键的地方在与建图,我们把横着的一条(两边为2),只能选一个的抽出来。把竖着的一条(两边为2),只能选一个的抽出来。发现选择一个点放守卫,即为横的和竖着的交点,进行连边,跑二分图保证了,横的竖的一条每条最多用一次。问题就解决了。

点数最多n2,还达不到,n2/2,因为一个点的形成两边都要是墙,并且陷阱也不能连边。

Code

  1. // <guards.cpp> - Fri Sep 23 08:09:06 2016
  2. // This file is made by YJinpeng,created by XuYike's black technology automatically.
  3. // Copyright (C) 2016 ChangJun High School, Inc.
  4. // I don't know what this program is.
  5. #include <iostream>
  6. #include <vector>
  7. #include <algorithm>
  8. #include <cstring>
  9. #include <cstdio>
  10. #include <cstdlib>
  11. #include <cmath>
  12. #include <ctime>
  13. #define MOD 1000000007
  14. #define INF 1e9
  15. using namespace std;
  16. typedef long long LL;
  17. const int MAXN=210;
  18. const int MAXM=40010;
  19. inline int max(int &x,int &y) {return x>y?x:y;}
  20. inline int min(int &x,int &y) {return x<y?x:y;}
  21. inline int gi() {
  22. register int w=0,q=0;register char ch=getchar();
  23. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  24. if(ch=='-')q=1,ch=getchar();
  25. while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
  26. return q?-w:w;
  27. }
  28. int match[MAXM],X[MAXM],Y[MAXM];
  29. int a[MAXN][MAXN],x[MAXN][MAXN],y[MAXN][MAXN];
  30. vector<int>b[MAXM];int f[MAXM],cnt;
  31. inline void add(int u,int v){b[u].push_back(v);}
  32. bool dfs(int x){
  33. if(f[x]==cnt)return 0;
  34. int num=b[x].size();f[x]=cnt;
  35. for(int i=0;i<num;i++){
  36. int nex=b[x][i];
  37. if(match[nex]==-1||dfs(match[nex])){
  38. match[x]=nex;match[nex]=x;/*f[x]=0;*/return 1;
  39. }
  40. }//f[x]=0这句害死人,因为下一次又会再次调用dfs
  41. return 0;
  42. }
  43. int main()
  44. {
  45. freopen("guards.in","r",stdin);
  46. freopen("guards.out","w",stdout);
  47. int n=gi(),m=gi(),t1=-1,t2=-1,ans=0;
  48. for(int i=1;i<=n;i++)a[i][0]=2;
  49. for(int i=1;i<=m;i++)a[0][i]=2;
  50. for(int i=1;i<=n;i++)
  51. for(int j=1;j<=m;j++){
  52. a[i][j]=gi();
  53. if(a[i][j-1]==2)++t1,X[t1]=i;
  54. x[i][j]=t1;
  55. }
  56. for(int j=1;j<=m;j++)
  57. for(int i=1;i<=n;i++){
  58. if(a[i-1][j]==2)++t2,Y[t2]=j;
  59. y[i][j]=t2;
  60. }
  61. for(int i=1;i<=n;i++)
  62. for(int j=1;j<=m;j++){
  63. if(a[i][j])continue;
  64. add(x[i][j],y[i][j]+t1+1);
  65. }
  66. memset(f,false,sizeof(f));
  67. for(int i=0;i<=t1+t2+1;i++)match[i]=-1;
  68. for(int i=0;i<=t1;i++)
  69. if(match[i]==-1){
  70. cnt++;if(dfs(i))++ans;
  71. //memset(f,0,sizeof(f));这个不好复杂度高
  72. }
  73. printf("%d\n",ans);
  74. for(int i=0;i<=t1;i++)
  75. if(match[i]!=-1)printf("%d %d\n",X[i],Y[match[i]-t1-1]);
  76. return 0;
  77. }

Compare

Codevs提交不了(没有SPJ)WA

我在这里发一个pascal的spj

  1. Program Compare;
  2. { 本程序为A+B的比较程序,本程序仅作为比较程序的样例。 }
  3. var
  4. Inf, Ouf, Std, Log: String;
  5. procedure GetParams;
  6. begin
  7. Inf := Paramstr(1); { 标准输入文件 }
  8. Ouf := Paramstr(2); { 选手输出文件 }
  9. Std := Paramstr(3); { 标准输出文件 }
  10. Log := Paramstr(5); { 结果文件 }
  11. end;
  12. procedure WriteLog(Score: integer; Description: String);
  13. { 将比较结果写入结果文件中,其中Score为选手的得分百分比,Description为注释。 }
  14. begin
  15. assign(output, Log); rewrite(output);
  16. //writeln(Score*10, ' ', Description);
  17. writeln(Score*10);
  18. close(output);
  19. Halt;
  20. end;
  21. var
  22. a:array[1..200,1..200]of longint;
  23. x,y:array[1..40000]of longint;
  24. m,n: Longint; { AB的值 }
  25. Sum: Longint; { A+B的标准答案 }
  26. Ans: Longint; { 选手的输出 }
  27. procedure InfRead;
  28. { 从输入文件中输入AB的值。 }
  29. var
  30. i,j:longint;
  31. begin
  32. {$i-}
  33. assign(input, Inf); reset(input);
  34. readln(m,n);
  35. for i:=1 to m do
  36. for j:=1 to n do
  37. read(a[i,j]);
  38. close(input);
  39. {$i+}
  40. if IOResult <> 0 then WriteLog(0, '输入文件错误!');
  41. end;
  42. procedure StdRead;
  43. { 从标准输出中输入AB的和 }
  44. begin
  45. {$i-}
  46. assign(input, Std); reset(input);
  47. read(Sum);
  48. close(input);
  49. {$i+}
  50. if IOResult <> 0 then begin
  51. WriteLog(0, '标准输出文件错误!');
  52. halt;
  53. end;
  54. end;
  55. procedure OufRead;
  56. { 从输出中输入选手的答案 }
  57. var
  58. i:longint;
  59. begin
  60. {$i-}
  61. assign(input, Ouf); reset(input);
  62. readln(Ans);
  63. if Ans<Sum then begin writelog(0,'守卫放置不是最优的'); close(input); halt; end;
  64. for i:=1 to ans do
  65. begin
  66. readln(x[i],y[i]);
  67. a[x[i],y[i]]:=3;
  68. end;
  69. close(input);
  70. {$i+}
  71. if IOResult <> 0 then WriteLog(0, '输出文件错误!');
  72. if ans=sum then writelog(1, '正确')
  73. else writelog(0, '错误');
  74. end;
  75. procedure Check;
  76. { 比较选手的解与标准答案 }
  77. var
  78. i,j,k:longint;
  79. begin
  80. for i:=1 to ans do
  81. begin
  82. j:=x[i];k:=y[i];
  83. if a[j,k]=1 then begin writelog(0,'踩在陷阱上'); halt; end;
  84. j:=x[i]+1;
  85. while (a[j,k]<>2)and(j<=n) do
  86. begin
  87. if a[j,k]=3 then begin writelog(0,'有互相攻击的一对士兵'); halt; end;
  88. inc(j);
  89. end;
  90. j:=x[i]-1;
  91. while (a[j,k]<>2)and(j>0) do
  92. begin
  93. if a[j,k]=3 then begin writelog(0,'有互相攻击的一对士兵'); halt; end;
  94. dec(j);
  95. end;
  96. j:=x[i];k:=y[i]+1;
  97. while (a[j,k]<>2)and(k<=m) do
  98. begin
  99. if a[j,k]=3 then begin writelog(0,'有互相攻击的一对士兵'); halt; end;
  100. inc(k);
  101. end;
  102. k:=y[i]-1;
  103. while (a[j,k]<>2)and(k>0) do
  104. begin
  105. if a[j,k]=3 then begin writelog(0,'有互相攻击的一对士兵'); halt; end;
  106. dec(k);
  107. end;
  108. end;
  109. writelog(1,'正确');
  110. end;
  111. begin
  112. GetParams;
  113. InfRead;
  114. StdRead;
  115. OufRead;
  116. // Check;
  117. end.

【Codevs3567】宫廷守卫的更多相关文章

  1. 【题解】宫廷守卫 [P1263]

    [题解]宫廷守卫 [P1263] 传送门:宫廷守卫 \([P1263]\) [题目描述] 给出一个 \(n*m\) 的方格图,分别用整数 \(0,1,2\) 表示空地.陷阱.墙,空地上可以放置守卫,如 ...

  2. 洛谷P1263 宫廷守卫

    P1263 宫廷守卫 题目描述 从前有一个王国,这个王国的城堡是一个矩形,被分为M×N个方格.一些方格是墙,而另一些是空地.这个王国的国王在城堡里设了一些陷阱,每个陷阱占据一块空地. 一天,国王决定在 ...

  3. 洛谷 P1263 宫廷守卫

    被这道题折腾了 \(2\) 个小时. 按照题意,每个守卫的上下左右四个方向上应当都是墙,而不能出现其他的守卫. 如图是一个合法的放置方案.每个守卫四个方向上都是墙(包括宫廷外墙). 如图是一个非法的放 ...

  4. 洛谷P1263 || 巴蜀2311 宫廷守卫

    题目描述 从前有一个王国,这个王国的城堡是一个矩形,被分为M×N个方格.一些方格是墙,而另一些是空地.这个王国的国王在城堡里设了一些陷阱,每个陷阱占据一块空地. 一天,国王决定在城堡里布置守卫,他希望 ...

  5. 二分图&网络流初步

    链接 : 最小割&网络流应用 EK太低级了,不用. 那么请看:#6068. 「2017 山东一轮集训 Day4」棋盘,不用EK你试试? dinic模板及部分变形应用见zzz大佬的博客:网络流学 ...

  6. 【TYVJ1864】[Poetize I]守卫者的挑战 概率与期望

    [TYVJ1864][Poetize I]守卫者的挑战 描述 打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻着关押applepi的监狱的所在地.突然,眼前一道亮光闪过."我 ...

  7. effective java —— 终结方法守卫者

    目录: effective java —— 终结方法守卫者 effective java 第2章:创建和销毁对象.第7条 : 避免使用终结方法.最后的“终结方法守卫者 (finalizer guard ...

  8. TYVJ1864 守卫者的挑战

    P1864 [Poetize I]守卫者的挑战 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜 ...

  9. LA 3177 长城守卫

    n为偶数的时候比较简单,就是相邻两个守卫的礼物和的最大值. 首先这是个下限,其次这个值也满足题目要求,所以这就是答案了. 当n为奇数的时候上限是守卫索要礼物的最大值的三倍. 这也很容易理解,比如n=5 ...

随机推荐

  1. python利用requests统计1个接口的响应时间

    参照 https://www.cnblogs.com/yoyoketang/p/8035428.html requests统计接口的响应时间有2种方式 r.elapsed.total_seconds( ...

  2. chr()返回值是当前整数对应的 ASCII 字符。

    #chr() 用一个范围在 range(256)内的(就是0-255)整数作参数,返回一个对应的字符.#返回值是当前整数对应的 ASCII 字符.1 import random input_m =10 ...

  3. SpringBoot中如何使用jpa和jpa的相关知识总结

    jpa常用的注解: 注解 解释 @Entity 声明类为实体或表. @Table 声明表名. @Basic 指定非约束明确的各个字段. @Embedded 指定类或它的值是一个可嵌入的类的实例的实体的 ...

  4. 反片语(Ananagrams,Uva 156)

    输入一些单词,找出所有满足如下条件的单词:该单词不能通过字母重排,得到输入文 本中的另外一个单词.在判断是否满足条件时,字母不分大小写,但在输出时应保留输入中 的大小写,按字典序进行排列(所有大写字母 ...

  5. Python面向对象类的特殊成员方法

    类的特殊成员方法:1.__doc__ : 打印类下面的注释 2.__module__和__class__:from lib.aa import C输出类被导出的模块名lib.aa,输出类的模块名和类名 ...

  6. LINUX-JPS工具

    JPS工具 jps(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/u ...

  7. 九九乘法表-Java

    public class Test1 { public static void main(String[] args){ for(int i=1;i<=9;i++){ for(int j=1;j ...

  8. 关于 startup_stm32f10x_hd.s 这个文件的一些说明

    关于 startup_stm32f10x_hd.s 这个文件的一些说明 startup_stm32f10x_hd.s 是一个启动文件,里面是使用汇编语言写好的基本程序,当STM32 芯片上电启动的时候 ...

  9. 自定义Realm

    [单Realm] 1) jar包 2) 实现自定义Realm public class RealmOne implements Realm{ /** * 获取基本类名 */ @Override pub ...

  10. NOIP2011 提高组合集

    NOIP 2011 提高组合集 D1 T1 铺地毯 模拟,题目让你干啥你就干啥 #include <iostream> #include <cstdio> using name ...