信息学奥赛一本通 1395:烦人的幻灯片(slides)
【题目链接】
ybt 1395:烦人的幻灯片(slides)
【题目考点】
1. 图论:拓扑排序
【解题思路】
先理解题意:
如图,每张幻灯片是一个矩形,在该矩形范围内有一个位置写了这张幻灯片的编号。但实际情况是幻灯片是透明的而且可能是重叠的,编号的颜色都是相同的,一眼看上去看不出一个编号是写在哪张幻灯片上的。现在按照字母编号给出每张幻灯片矩形的位置、同时给出每个数字编号的位置,写出字母编号和数字编号的对应关系。
即给出A幻灯片上的编号是什么,B幻灯片上的编号是什么……
如果存在多种字母和编号的对应关系,或不存在可行的对应关系,都要输出None。
可以将幻灯片和数字编号都想像成顶点,如果编号X在幻灯片Y的范围内,那么顶点Y到顶点X有一条有向边。上图转为的拓扑图如图。
而后可以进行类似拓扑排序的操作:
先将所有入度为1的顶点入队。
每次循环出队一个顶点X,如果到达顶点X的边只有一条,是从顶点Y出发到顶点X的边,那么顶点X的入度为1,这意味着顶点X代表的编号只存在于顶点Y代表的幻灯片的范围内,因此顶点X代表的编号一定为顶点Y代表的幻灯片的编号。
而后同时把顶点X、顶点Y删掉,自然也把从Y出发的边都删掉,再看哪些顶点入度为1,将入度为1的顶点入队。
重复上述操作。
如果最后删掉的表示编号顶点的数量等于n,说明每张幻灯片都找到了与其对应的编号。
如果最后删掉的表示编号顶点的数量小于n,说明最后有一些编号不能确定到底算是哪个幻灯片的编号,编号和幻灯片有多种对应关系,或没有对应关系,应该输出None。
【题解代码】
解法1:拓扑排序
#include<bits/stdc++.h>
using namespace std;
#define N 30
struct Rect
{int xmin, xmax, ymin, ymax;bool isIn(int x, int y){return x >= xmin && x <= xmax && y >= ymin && y <= ymax; }
} slide[N];//slide[i]:字母编号为i的幻灯片
bool edge[N][N];//edge[i][j]:字母编号为i的幻灯片是否压着数字j
int n, deg[N], rec[N];//rec[i]:字母编号为i的幻灯片对应的数字
int find(int u)//对于入度只有1的数字顶点u,寻找与其对应的唯一字母顶点
{for(int k = 0; k < n; ++k)if(edge[k][u])//从字母k到数字u有边 return k;
}
bool topoSort()//返回是否成功完成类拓扑排序(删除数字结点数量是否为n)
{int num = 0;//成功删除的数字结点数量 queue<int> que;for(int i = 1; i <= n; ++i)//开始进行类拓扑排序,删除入度为1的数字顶点 if(deg[i] == 1)que.push(i);while(que.empty() == false){int u = que.front(), k = find(u);//字母k指向数字uque.pop();rec[k] = u;//字母k与数字u对应num++;for(int i = 1; i <= n; ++i) if(edge[k][i])//删除从字母k到数字i的边 {edge[k][i] = false;if(--deg[i] == 1)//如果数字i入度为1,则入队 que.push(i);} }return num == n;
}
int main()
{int x, y;cin >> n;for(int i = 0; i < n; ++i)cin >> slide[i].xmin >> slide[i].xmax >> slide[i].ymin >> slide[i].ymax;for(int i = 1; i <= n; ++i){cin >> x >> y;for(int j = 0; j < n; ++j) if(slide[j].isIn(x, y))//如果x,y在幻灯片字母编号j的范围内{edge[j][i] = true;//幻灯片j压着数字ideg[i]++;//数字编号i的入度增加 } }bool res = topoSort();if(res)//配对成功 {for(int i = 0; i < n; ++i)cout << char('A'+i) << ' ' << rec[i] << endl; }elsecout << "None";return 0;
}