网络流 -- Shooting Contest(二分匹配)

来源:互联网 发布:绝对萌域淘宝店名 编辑:程序博客网 时间:2024/05/04 09:34
Shooting Contest
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 2279 Accepted: 809 Special Judge

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

24 42 43 41 31 45 51 52 43 42 42 3

Sample Output

2 3 1 4NO

Source

CEOI 1997

/*一开始拿到这道题一下子就想到了二分图的最大匹配,然后想来想去没有把图的映射关系想明白,就放弃二分了,转去想DP,但是想来想去也没有找到子结构关系,于是又转回二分图。经过仔细分析终于找到了规律,首先如果列数少于行数是肯定要输出NO的,因为一列只能覆盖一行,所以不能覆盖所有行。接下来就是建图了,以行为左,列为右建立二分图,然后对二分图算最大匹配total,如果total < 行数则输出NO,否则依次遍历所有列并输出其对应的行即pre,对于pre[i] != 0的就输出pre[i]否则,从i可以连的行中随便找一个输出即可*/#include <iostream>   #define MAX_N 1000   using namespace std;bool v[MAX_N + 1];int pre[MAX_N + 1];int rowCol[MAX_N + 1][MAX_N + 1];int colRow[MAX_N + 1];int r, c;bool canGo(int from){<span style="white-space:pre"></span>int num = rowCol[from][0];<span style="white-space:pre"></span>int p, to;<span style="white-space:pre"></span>for (p = 1; p <= num; p++)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>to = rowCol[from][p];<span style="white-space:pre"></span>if (!v[to])<span style="white-space:pre"></span>{<span style="white-space:pre"></span>v[to] = true;<span style="white-space:pre"></span>if (pre[to] == 0 || canGo(pre[to]))<span style="white-space:pre"></span>{<span style="white-space:pre"></span>pre[to] = from;<span style="white-space:pre"></span>return true;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}<span style="white-space:pre"></span>return false;}int main(){<span style="white-space:pre"></span>int caseN, i;<span style="white-space:pre"></span>FILE *file = freopen("in13.txt", "r", stdin);<span style="white-space:pre"></span>if (!file)<span style="white-space:pre"></span>return 1;<span style="white-space:pre"></span>scanf("%d", &caseN);<span style="white-space:pre"></span>while (caseN--)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>int row1, row2;<span style="white-space:pre"></span>memset(rowCol, 0, sizeof(rowCol));<span style="white-space:pre"></span>scanf("%d%d", &r, &c);<span style="white-space:pre"></span>for (i = 1; i <= c; i++)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>scanf("%d%d", &row1, &row2);<span style="white-space:pre"></span>rowCol[row1][0]++;<span style="white-space:pre"></span>rowCol[row1][rowCol[row1][0]] = i;<span style="white-space:pre"></span>colRow[i] = row1;<span style="white-space:pre"></span>rowCol[row2][0]++;<span style="white-space:pre"></span>rowCol[row2][rowCol[row2][0]] = i;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>int total = 0;<span style="white-space:pre"></span>bool can = true;<span style="white-space:pre"></span>if (c < r) can = false;<span style="white-space:pre"></span>else<span style="white-space:pre"></span>{<span style="white-space:pre"></span>memset(pre, 0, sizeof(pre));<span style="white-space:pre"></span>for (i = 1; i <= r; i++)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>memset(v, 0, sizeof(v));<span style="white-space:pre"></span>if (canGo(i)) total++;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>if (total < r) can = false;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>if (!can) printf("NO\n");<span style="white-space:pre"></span>else<span style="white-space:pre"></span>{<span style="white-space:pre"></span>for (i = 1; i <= c; i++)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>if (i != 1) printf(" ");<span style="white-space:pre"></span>if (pre[i] != 0) printf("%d", pre[i]);<span style="white-space:pre"></span>else printf("%d", colRow[i]);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>printf("\n");<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}<span style="white-space:pre"></span>return 0;}


0 0