Sorting Slides
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 5676 | Accepted: 2188 |
Description
Professor Clumsey is going to give an important talk this afternoon. Unfortunately, he is not a very tidy person and has put all his transparencies on one big heap. Before giving the talk, he has to sort the slides. Being a kind of minimalist, he wants to do this with the minimum amount of work possible.
The situation is like this. The slides all have numbers written on them according to their order in the talk. Since the slides lie on each other and are transparent, one cannot see on which slide each number is written.
Well, one cannot see on which slide a number is written, but one may deduce which numbers are written on which slides. If we label the slides which characters A, B, C, ... as in the figure above, it is obvious that D has number 3, B has number 1, C number 2 and A number 4.
Your task, should you choose to accept it, is to write a program that automates this process.
Input
The input consists of several heap descriptions. Each heap descriptions starts with a line containing a single integer n, the number of slides in the heap. The following n lines contain four integers xmin, xmax, ymin and ymax, each, the bounding coordinates of the slides. The slides will be labeled as A, B, C, ... in the order of the input.
This is followed by n lines containing two integers each, the x- and y-coordinates of the n numbers printed on the slides. The first coordinate pair will be for number 1, the next pair for 2, etc. No number will lie on a slide boundary.
The input is terminated by a heap description starting with n = 0, which should not be processed.
Output
For each heap description in the input first output its number. Then print a series of all the slides whose numbers can be uniquely determined from the input. Order the pairs by their letter identifier.
If no matchings can be determined from the input, just print the word none on a line by itself.
Output a blank line after each test case.
Sample Input
4
6 22 10 20
4 18 6 16
8 20 2 18
10 24 4 8
9 15
19 17
11 7
21 11
2
0 2 0 2
0 2 0 2
1 1
1 1
0
Sample Output
Heap 1
(A,4) (B,1) (C,2) (D,3)
Heap 2
none。
题目大意 : 有N个透明的卡片, 编号从1 到 N, 每个卡片都对应了某个英文字母, 由于是透明的,所以无法辨认哪个字母是属于哪张卡片(字母在卡片的范围内即为属于该卡片),现在让你输出所有的可以确定的字母属于卡片的组合,如果一个也无法确定, 输出 “none”
思路 : 在学二分图最大匹配完备图的必须边之前, 我找必须边都是通过删边,然后看删完这条边之后, 二分图是否还能达到之前的匹配数, 如果不能,说明该边是必须边, 有一道棋盘的题这样暴力做是能过的, 写这道题的时候我才知道必须边和可行边有他自己的写法。 可行边的概念是, 删除这条边之后, 二分图的最大匹配数不变, 但是他仍然可以做为二分图最大匹配中的一条边(换句话说就是存在增广路), 而必须边就是删除该边, 无法达到最大匹配。 具体做法是这样, 先跑一遍最大匹配, 然后形成了一些边, 不知道是不是必须边, 所以建一个图 :如果该边是匹配后的边, 将两点反向建图, 否则正向建图。 缩完点之后, 如果是之前最大匹配中的边, 他的两个点不在一个集合中, 那这条边一定是必须边, 而在一个集合中的,就是可行边, 不明白画几张图就会了,样例一就可以。最后处理一些细节,这道题就解决了。
Accepted code
#include<iostream>
#include<algorithm>
#include<functional>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & (-x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 2e3 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
struct Edge
{
int v, next;
}edge[MAXN << 1];
struct node
{
int lx, rx, ly, ry; // 范围
}p[MAXN];
vector <int> e[MAXN << 1];
int head[MAXN], dfn[MAXN], low[MAXN], as[MAXN]; // as为必须边
int pre[MAXN], suo[MAXN], n, cnt, tot, scnt, X; // pre为最大匹配的边
bool vis[MAXN];
stack <int> st;
void init() {
for (int i = 1; i <= n; i++) e[i].clear();
MEM(head, -1); MEM(dfn, 0); MEM(low, 0);
MEM(vis, 0); MEM(pre, 0); MEM(suo, 0); MEM(as, 0);
cnt = tot = scnt = 0;
}
void add(int from, int to) {
edge[++cnt].v = to;
edge[cnt].next = head[from];
head[from] = cnt;
}
bool find_(int x) {
for (int i = 0; i < SZ(e[x]); i++) {
int vi = e[x][i];
if (!vis[vi]) {
vis[vi] = true;
if (!pre[vi] || find_(pre[vi])) {
pre[vi] = x;
return true;
}
}
}
return false;
}
void tarjan(int x) {
dfn[x] = low[x] = ++tot;
vis[x] = 1; st.push(x);
for (int i = head[x]; i != -1; i = edge[i].next) {
int vi = edge[i].v;
if (!dfn[vi]) {
tarjan(vi);
low[x] = min(low[x], low[vi]);
}
else if (vis[vi]) low[x] = min(low[x], dfn[vi]);
}
if (dfn[x] == low[x]) {
scnt++;
int k;
do {
k = st.top();
st.pop();
vis[k] = 0;
suo[k] = scnt; // 存到一个集合
} while (k != x);
}
}
int main()
{
while (~sc("%d", &n) && n) {
init();
for (int i = 1; i <= n; i++) sc("%d %d %d %d", &p[i].lx, &p[i].rx, &p[i].ly, &p[i].ry);
for (int i = n + 1; i <= 2 * n; i++) {
int xi, yi;
sc("%d %d", &xi, &yi);
for (int j = 1; j <= n; j++) {
if (xi >= p[j].lx && xi <= p[j].rx && yi >= p[j].ly && yi <= p[j].ry)
e[j].push_back(i); // 存边
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
MEM(vis, 0);
if (find_(i)) ans++; // 先跑一遍最大匹配
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < SZ(e[i]); j++) {
int ui = i, vi = e[i][j];
if (pre[vi] == ui) add(vi, ui); // 是最大匹配中的边反向 }
}
MEM(vis, 0);
for (int i = 1; i <= 2 * n; i++) {
if (!dfn[i]) tarjan(i);
}
bool flag = 0;
for (int i = n + 1; i <= 2 * n; i++) {
for (int j = head[i]; j != -1; j = edge[j].next) {
int uu = i, vv = edge[j].v;
int ui = suo[uu], vi = suo[vv]; // 定义如上所述
if (pre[uu] == vv && ui != vi) { flag = 1; as[vv] = uu; }
}
}
printf("Heap %d\n", ++X);
if (!flag) { printf("none\n\n"); continue; } // 注意判断是否存在
for (int i = 1; i <= n; i++) if (as[i] - n > 0) printf("(%c,%d) ", i + 'A' - 1, as[i] - n);
printf("\n\n");
}
return 0;
}