信奥 一本通:拓扑排序:1395 计算每个结点能够在哪几张幻灯片出现

李教授将于今天下午作一次非常重要的演讲。不幸的事他不是一个非常爱整洁的人,他把自己演讲要用的幻灯片随便堆在了一起。因此,演讲之前他不得不去整理这些幻灯片。作为一个讲求效率的学者,他希望尽可能简单地完成它。教授这次演讲一共要用n张幻灯片(n<=26),这n张幻灯片按照演讲要使用的顺序已经用数字1~n编了号。因为幻灯片是透明的,所以我们不能一下子看清每一个数字所对应的幻灯片。

现在我们用大写字母A,B,C……再次把幻灯片依次编号。你的任务是编写一个程序,把幻灯片的数字编号和字母编号对应起来,显然这种对应应该是唯一的;若出现多种对应的情况或是某些数字编号和字母编号对应不起来,我们称对应是无法实现的。

【输入】

第一行只有一个整数n,表示有n张幻灯片,接下来的n行每行包括4个整数xmin,xmax,ymin,ymax(整数之间用空格分开)为幻灯片的坐标,这n张幻灯片按其在文件中出现的顺序从前到后依次编号为A,B,C……,再接下来的n行依次为n个数字编号的坐标x,y,显然在幻灯片之外是不会有数字的。

【输出】

若是对应可以实现,输出文件应该包括n行,每一行为一个字母和一个数字,中间以一个空格隔开,并且每行以字母的升序排列,注意输出的字母要大写并且定格;反之,若是对应无法实现,在文件的第一行顶格输出None即可。首行末无多余的空格。

【输入样例】

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

【输出样例】

A 4
B 1
C 2
D 3
 思路:
利用dfs 搜索,匹配,优先搜索度为1的点,只有一种选择情况 
记录选择的幻灯片 i,然后 删掉i,更新其它点  到i点的 情况,度减少1,如果度为1的话,其它点,又可以搜索选择幻灯片了
直到n个点都选择了合适的幻灯片 
int ans[30]; 第i张 幻灯片 选择的点 的情况(不是 第i点选择幻灯片的情况),可以选择dfs 或者bfs 都可以
*/ 
*/ 
#include<bits/stdc++.h>
using namespace std;
// 幻灯片定义 
struct node
{
int xl,xr;
int yl,yr;
}nd[30];
// 点的定义 
struct point{
int x,y;
}p[30];
int n,sum=0;
int du[30];
int vis[30][30]; // 第i个点,可以选择 第j个幻灯片 
int ans[30];// 第i张 幻灯片 选择的点 的情况(不是 第i点选择幻灯片的情况) 
void bfs(int x)
{
queue<int> qu;
qu.push(x);//
while(qu.size()>0)
{
int nf=qu.front();qu.pop();
du[nf]--;sum++;
for(int i=1;i<=n;i++)
{
if(vis[nf][i]==1)
{
ans[i]=nf; //第i张幻灯片选择的是第nf结点.删掉i张幻灯片的选择情况
vis[nf][i]=0;
for(int j=1;j<=n;j++)
{
if(vis[j][i]==1)
{
vis[j][i]=0;
du[j]--;
if(du[j]==1)
{
qu.push(j);
}
}
}
}
}
}
//从度为1的结点x开始搜索,选择 
/*  
void dfs(int x) //从度为1的点开始 选择 幻灯片,说明只有一种可以选择 
{
du[x]--;
sum++;//已经选择的幻灯片的个数
for(int i=1;i<=n;i++) //计算这个点 选择的幻灯片的情况 
{
if(vis[x][i]) //x点选择 第i张幻灯片
{
ans[i]=x;// 第i张幻灯片选择的第x个点
vis[x][i]=0; //第x点 修改状态
// 删除删除幻灯片i被其它结点的选择情况(i已经被x选择了):
 for(int j=1;j<=n;j++)
 {
  if(vis[j][i]==1)
  {
  du[j]--;
  vis[j][i]=0;
  if(du[j]==1)
  {
  dfs(j);
 }
 }
 }
break;
 } 
 } 
}
*/ 
int main()
{
cin>>n;
int i;
for(i=1;i<=n;i++)
{
cin>>nd[i].xl>>nd[i].xr>>nd[i].yl>>nd[i].yr;
}
for(i=1;i<=n;i++)
{
cin>>p[i].x>>p[i].y;
}
// 计算每个点的度,可以在幻灯片里面的次数,暴力
for(i=1;i<=n;i++)
{
int cnt=0;
for(int j=1;j<=n;j++)
{
if(p[i].x>=nd[j].xl&&p[i].x<=nd[j].xr&&p[i].y>=nd[j].yl&&p[i].y<=nd[j].yr)
{
   vis[i][j]=1; //第i个点在第j张幻灯片上 
   cnt++;
}
}
du[i]=cnt; 
 } 
 for(i=1;i<=n;i++)
 {
  if(du[i]==1)
  {
  bfs(i);
 }
 }
 // 找完看sum是不是等于n,如果等的话,刚好,如果不等的话,
 if(sum<n)
 {
   printf("None"); 
   return 0;
 }
 for(i=1;i<=n;i++)
 {
  printf("%c %d\n",'A'+i-1,ans[i]);
 }
return 0;
}

  • 27
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值