[UVA663]Sorting Slides

同步自洛谷
[UVA663]Sorting Sides


思路

这道题目给出每个幻灯片的位置和标注字母的坐标,求字母与幻灯片的对应关系。

先不考虑是否唯一的问题。首先,我们知道,如果一个字母仅在一个幻灯片内,则关系是固定的。也就是说,我们每次找到一个这样的字母,然后记录关系,在把该幻灯片与其他字母的联系断开。


我们可以将该题转化为类似拓扑排序的题目。我们把转化成字母编号和幻灯片编号建立关系,如果编号为 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 的点加入队列。

循环结束,我们有几种情况:

  1. 无解,输出 none。此时循环的次数应小于点数;
  2. 输出结果(注意格式)。

所以这样就完了吗?其实并没有。幻灯片只能唯一对应某个数字。

也就是说,在寻找入度为 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值