思路
这道题目给出每个幻灯片的位置和标注字母的坐标,求字母与幻灯片的对应关系。
先不考虑是否唯一的问题。首先,我们知道,如果一个字母仅在一个幻灯片内,则关系是固定的。也就是说,我们每次找到一个这样的字母,然后记录关系,在把该幻灯片与其他字母的联系断开。
我们可以将该题转化为类似拓扑排序的题目。我们把转化成字母编号和幻灯片编号建立关系,如果编号为 x x x 的字母在该幻灯片 y y y 内,则连一条从 y y y 到 x x x 的边,并将 x x x 的入度加 1 1 1。
接下来我们找到一个入度为 1 1 1 的点(注意这里是 1 1 1,不是 0 0 0),将它放入队列 q q q 中。如果队列非空,则将队首弹出,记录关系,并且找到其对应的幻灯片 x x x,幻灯片 x x x 到其所连字母的边断开,入度减 1 1 1。这时将入度为 1 1 1 的点加入队列。
循环结束,我们有几种情况:
- 无解,输出 none。此时循环的次数应小于点数;
- 输出结果(注意格式)。
所以这样就完了吗?其实并没有。幻灯片只能唯一对应某个数字。
也就是说,在寻找入度为 0 0 0 的点时,定义一个变量记录入度为 0 0 0 的点的个数,如果变量大于 2 2 2,也输出 none。
其实一位大佬说这道题不能用拓扑排序,就是这一点的问题。
最后注意多组数据的问题,一定要清空,不要少清!!!
代码
#include<bits/stdc++.h>
using namespace std;
int d[30];
int xa[30], xb[30], ya[30], yb[30];
int ans[30], rd[30];
bool v[30][30];
queue<int> q;
int len = 0;
int n, T = 0;
int main(){
while(scanf("%d", &n) != EOF){
if(n == 0){
return 0;
}
len = 0;
memset(v, 0, sizeof(v));
for(int i = 1; i <= n; ++ i){
scanf("%d %d %d %d", &xa[i], &xb[i], &ya[i], &yb[i]);
}
for(int i = 1; i <= n; ++ i){
int x, y;
scanf("%d %d", &x, &y);
for(int j = 1; j <= n; ++ j){
if(x >= xa[j] && x <= xb[j] && y >= ya[j] && y <= yb[j]){
rd[i] ++;
v[j][i] = 1;
}
}
}
int sum = 0;
for(int i = 1; i <= n; ++ i){
if(rd[i] == 1){
q.push(i);
++ sum;
}
}
if(sum > 2){
++ T;
printf("Heap %d\n", T);
printf("none\n\n");
continue;
}
bool f = 1;
while(!q.empty()){
++ len;
int t = q.front();
q.pop();
sum = 0;
for(int j = 1; j <= n; ++ j){
if(v[j][t]){
ans[j] = t;
for(int k = 1; k <= n; ++ k){
if(v[j][k]){
-- rd[k];
v[j][k] = 0;
if(rd[k] == 1){
++ sum;
q.push(k);
ans[++ len] = k;
}
}
}
}
}
if(sum > 1){
++ T;
printf("Heap %d\n", T);
printf("none\n\n");
f = 0;
break;
}
}
if(!f){
continue;
}
++ T;
printf("Heap %d\n", T);
if(len < n){
printf("none");
}
else{
for(int i = 1; i <= n; ++ i){
printf("(%c,%d) ", i - 1 + 'A', ans[i]);
}
}
putchar('\n');
putchar('\n');
}
return 0;
}