Shooting Contest 射击比赛 [POJ1719] [CEOI1997] [一题多解]

Description(下有中文题意)

Welcome to the Annual Byteland Shooting Contest. Each competitor will shoot to a target which is a rectangular grid. The target consists of r*c squares located in r rows and c columns. The squares are coloured white or black. There are exactly two white squares and r-2 black squares in each column. Rows are consecutively labelled 1,..,r from top to bottom and columns are labelled 1,..,c from left to right. The shooter has c shots. 
A volley of c shots is correct if exactly one white square is hit in each column and there is no row without white square being hit. Help the shooter to find a correct volley of hits if such a volley exists. 
Example 
Consider the following target: 

Volley of hits at white squares in rows 2, 3, 1, 4 in consecutive columns 1, 2, 3, 4 is correct. 
Write a program that: verifies whether any correct volley of hits exists and if so, finds one of them.

Input

The first line of the input contains the number of data blocks x, 1 <= x <= 5. The following lines constitute x blocks. The first block starts in the second line of the input file; each next block starts directly after the previous one. 

The first line of each block contains two integers r and c separated by a single space, 2 <= r <= c <= 1000. These are the numbers of rows and columns, respectively. Each of the next c lines in the block contains two integers separated by a single space. The integers in the input line i + 1 in the block, 1 <= i <= c, are labels of rows with white squares in the i-th column.

Output

For the i-th block, 1 <= i <= x, your program should write to the i-th line of the standard output either a sequence of c row labels (separated by single spaces) forming a correct volley of hits at white squares in consecutive columns 1, 2, ..., c, or one word NO if such a volley does not exists.

Sample Input

2
4 4
2 4
3 4
1 3
1 4
5 5
1 5
2 4
3 4
2 4
2 3

Sample Output

 

2 3 1 4
NO

 

Hint

R,C<=1000

给你一个r*c的矩阵,然后这个矩阵每一列有两个格子是白色的,然后你在每列上开一枪,可以打这列的任意的白色格子,问你打到的格子所在的行数是不是包括所有行了,如果包括所有行输出你在1-c列打抢的格子的行,当然这可以是不唯一的(此题为SPJ (Special Judge)),如果打不到就输出NO。

 

Solution

这道题的解题方法可谓是千姿百态

一、网络流

n我们将表示列的点编号为1到C,表示行的点编号为C+1到C+R,如果一个白色方格处在第i行第j列,那么从点j向点C+i连一条弧,弧的容量为1。再增设一个源点S,从点S往点1到C间各连一条弧,弧的容量为1,又设一个汇点T,从点C+1到点C+R向汇点T连一条弧,弧的容量为1,那么从源点S到汇点T求最大流,求出的最大流量即为最多可以射击到的行数。各条流的路线则描述了具体的射击方案。
n显然,如果用网络流求出的最大流量比R小,则问题无解,否则我们可以根据网络流的结果求出该二分图的具体匹配方案。
红色的连线流量为1
蓝色的连线流量为0
选择的射击格即为:
(1,3), (2,1), (3,2), (4,4)
网络流算法经过优化,时间复杂度可以达到O(C*(n+4C+4R))
 
 
二、二分图最大匹配
建图方法跟上面一样,换做二分图最大匹配(可以用匈牙利算法)算就行了
 

、贪心

1、统计所有行包含的白格数
2、从还没有射击格的行中选出一个白格数最少的
3、检查所选的行
 (1)若所选行的白格数为0,则输出无解;
 (2)否则从所选行的白格中任选一个作为射击格,并将与该格同列的另一个白格所处行的白格数减1
4、返回到第2步,直到所有的行都有射击格。
5、若还有列没有选射击格,则在该列任选一白格作为射击格即可
 
上面的贪心方法非常高效:
时间复杂度为O(R´C),如果在程序中使用堆优化,时间复杂度将降为O(R´log2C)。空间复杂度是线性的,而且非常容易实现。
现在关键的问题就是——如何证明它的正确性?
 
用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,继续下去所有行就都已选取了射击格了。
因此,如果原问题有解,该贪心方法一定能找到一种正确的方案。由此可以证明,此贪心方法是正确的。确定贪心标准。
原文地址:https://www.cnblogs.com/ibilllee/p/7694265.html