poj 1719 Shooting Contest
http://poj.org/problem?id=1719
Shooting Contest
Time Limit: 1000MS | Memory Limit: 10000K | |||
Total Submissions: 4135 | Accepted: 1521 | 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.
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.
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
题意比较难理解,题意弄懂后这道题就比较简单,套用匈牙利算法求最大匹配
题目大意:r*c的矩阵,矩阵由白格子和黑格子组成,每一列有两个格子是白色的剩下的为黑色,每一列射击一发子弹击中白色格子,问是否所有行都有白色格子被击中
数据分析:
2//数据组数 4 4//行r 列c 2 4//第1列的第2行和第4行是白色格子
3 4//第2列的第3行和第4行是白色格子
1 3//第3列的第1行和第3行是白色格子
1 4// ...
1.如果 r > c , c列射击完后仍会有行没有被射击过;
2.要从每一列开始射击并射中白色格子,即将行r和列c作为X,Y集合,白色格子部分进行匹配,得到最大匹配值ans
1>如果ans==r
(1)如果每一列都有匹配(即都能射中某一行的白色格子)就输出与该列匹配的行(即该列击中的的白色格子所在的行)
(2)如果某一列没有找到匹配的格子,那个只要在该行任意选择一个白色的格子就可以了,输出该白色格子所在的行
2>如果ans>r或者ans<r都无法满足每行都被射击过
#include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> #include<queue> #include<algorithm> #define INF 0x3f3f3f3f #define N 1010 using namespace std; int G[N][N], vis[N], used[N]; int r, c; bool Find(int u) { int i; for(i = 1 ; i <= c ; i++) { if(!vis[i] && G[u][i]) { vis[i] = 1; if(!used[i] || Find(used[i])) { used[i] = u; return true; } } } return false; }//匈牙利 int main() { int a, b, i, t; scanf("%d", &t); while(t--) { scanf("%d%d", &r, &c); if(r > c) { printf("NO\n"); continue; }//如果 r > c , c列射击完后仍会有行没有被射击过 memset(G, 0, sizeof(G)); for(i = 1 ; i <= c ; i++) { scanf("%d%d", &a, &b); G[a][i] = G[b][i] = 1;//第i列个第a行和第b行是白色格子 } memset(used, 0, sizeof(used)); int ans = 0; for(i = 1 ; i <= r ; i++) { memset(vis, 0, sizeof(vis)); if(Find(i)) ans++; } if(ans == r) { for(i = 1 ; i <= c ; i++) { if(used[i] != 0)//如果每一列都有匹配(即都能射中某一行的白色格子)就输出与该列匹配的行(即该列击中的的白色格子所在的行) printf("%d ", used[i]); else { for(int j = 1 ; j <= r ; j++) { if(G[j][i]) { printf("%d ", j); break; } } }//如果某一列没有找到匹配的格子,那个只要在该行任意选择一个白色的格子就可以了,输出该白色格子所在的行; } printf("\n"); } else//如果ans>r或者ans<r都无法满足每行都被射击过 printf("NO\n"); } return 0; }