zoukankan      html  css  js  c++  java
  • 射击比赛 (POJ 1719) 题解

    【问题描述】

         我们假设射击的目标是一个由R*C(2≤R≤C≤ 1000)个小方格组成的矩形网格。网格中每一列恰有2个白色的小方格和R-2个黑色的小方格。定义网格的行从顶至底编号为1~R,列从左至右编号为1~C。 射击者可射击C次。在连续的C次射击中,若每列恰好有一个白色的方格被射中,且不存在无白色方格被射中的行,这样的射击才是正确的。现给出N组数据,对于每组数据,如果存在正确的射击方法,则要求找到它,若不存在,输出NO。

    【样例输入】

        2
        4 4

        2 4

        3 4

        1 3

        1 4

        5 5

        1 5

        2 4

        3 4

        2 4

        2 3

    【样例输出】

        2 3 1 4

        NO

    【解题思路】

         本题为1997年CEOI最后一题,解题的思路主要在于贪心策略与贪心的证明。

        贪心策略:

        1、统计所有行包含的白格数。

        2、从还没有射击格的行中选出一个白格数最少的。

        3、检查所选的行 (1)若所选行的白格数为0,则输出无解; (2)否则从所选行的白格中任选一个作为射击格,并将与该格同列的另一 个白格所处行的白格数减1。

        4、返回到第2步,直到所有的行都有射击格。

        5、若还有列没有选射击格,则在该列任选一白格作为射击格即可。

       贪心证明:

       用h[i]表示第i行的白格数。如果最开始的时候: ①min{h[i]}=0:第i行已经没有办法找到可作为射击格的白格,那么问题只能无解。        ②min{h[i]}=1:那么第i行的这一个白格必须要作为射击格,否则将因第i行没有射击格而造成问题无解。

       ③min{h[i]}≥2:那么在这一 行任选一个白格,顶多只会造成剩余行中有一行h值为1,再处理那一行,最多也只会再造成剩余行中有一行h   值为1,如此往复,将保持h值为1的行数不超过1行,最后最坏的情况也是造成最后一行的h值为1,继续下去所有行就都已选取了射击格了。因此,如果原问题有解,该贪心方法一定能找到一种正确的方案。由此可以证明,此贪心方法是正确的。确定贪心标准。

    【代码实现】

     1 var a:array[1..1000] of longint;
     2     b:array[1..1000,1..1000] of boolean;
     3     fr,fc:array[1..1000] of boolean;
     4     ans:array[1..1000] of longint;
     5     n,i,j,r,c,x1,x2,k,pos,min,code,q:longint;
     6     flag:boolean;
     7 begin
     8  readln(code);
     9  for q:=1 to code do
    10   begin
    11    fillchar(fr,sizeof(fr),false);
    12    fillchar(fc,sizeof(fc),false);
    13    fillchar(a,sizeof(a),0);
    14    fillchar(b,sizeof(b),0);//注意初始化,没初始化WA几次……
    15    readln(r,c);
    16    for i:=1 to c do
    17     begin
    18      readln(x1,x2);
    19      b[x1,i]:=true;b[x2,i]:=true;
    20      inc(a[x1]);inc(a[x2]);
    21     end;
    22    repeat
    23     min:=maxlongint;
    24     flag:=true;
    25     for i:=1 to r do
    26      if not(fr[i]) then
    27       break;
    28     if not(fr[i]) then
    29      flag:=false;
    30     if flag then break;
    31    for i:=1 to r do
    32     if (a[i]<min)and(not(fr[i])) then
    33      begin
    34       min:=a[i];
    35       pos:=i;
    36      end;
    37    if a[pos]=0 then
    38     begin
    39      writeln('NO');
    40      break;
    41     end;
    42    fr[pos]:=true;
    43    for j:=1 to c do
    44     if (b[pos,j])and(not(fc[j])) then
    45      begin
    46       ans[j]:=pos;fc[j]:=true;
    47       for k:=1 to r do
    48        if (b[k,j])and(k<>pos) then
    49         dec(a[k]);
    50       break;
    51      end;
    52    until flag;
    53    if a[pos]=0 then
    54     continue;
    55    for i:=1 to c do
    56     if ans[i]=0 then
    57      for j:=1 to r do
    58       if b[j,i] then
    59        begin
    60         ans[i]:=j;
    61         break;
    62        end;
    63    write(ans[1]);
    64    for i:=2 to c do
    65     write(' ',ans[i]);
    66    writeln;
    67   end;
    68 end.
    View Code

  • 相关阅读:
    命令练习题2
    l命令练习题1
    命令用法习题,yum仓库的创建 chapter02
    网络基础知识
    Linux常用的命令及使用方法
    Linux 常见的常识及常用快捷键方式
    一条命令解决mac版本python IDLE无法输入中文问题
    RS232串口的Windows编程纪要
    在龙芯小本上安装Debain8.10
    mac电脑进行可见光通信实验要点
  • 原文地址:https://www.cnblogs.com/PengBoLiuXu/p/4486120.html
Copyright © 2011-2022 走看看