描述:Baidu年会安排了一场时装秀节目。N名员工将依次身穿盛装上台表演。表演的顺序是通过一种“画线”抽签的方式决定的。
首先,员工们在一张白纸上画下N条平行的竖线。在竖线的上方从左到右依次写下1至N代表员工的编号;在竖线的下方也从左到右依次写下1至N代表出场表演的次序。
接着,员工们随意在两条相邻的竖线间添加垂直于竖线的横线段。
最后,每位员工的出场顺序是按如下规则决定的:每位员工从自己的编号开始用手指沿竖线向下划,每当遇到横线就沿横线移动到相邻的竖线上去,直到手指到达竖线下方的出场次序编号。这时手指指向的编号就是该员工的出场次序。例如在下图的例子中,度度熊将第二名出场,第一名出场的是员工4。
员工在画横线时,会避免在同一位置重复画线,并且避免两条相邻的横线连在一起。即下图所示的情况是不会出现的:
给定一种画线的方案,员工编号为K的度度熊想知道自己是不是第一位出场表演的。如果不是,度度熊想知道自己能不能通过增加一条横线段来使得自己变成第一位出场表演。
输入
为了描述方便,我们规定写有员工编号的方向是y轴正方向(即上文中的竖线上方),写有出场次序的方向是y轴负方向(即上文中的竖线下方)。竖线沿x轴方向(即上文中从左到右)依次编号1至N。于是,每条横线的位置都可以由一个三元组<xl, xr, y>确定,其中xl, xr是横线左右两个端点所在竖线的编号,y是横线的高度。
输入第一行是一个整数T(T <= 50),代表测试数据的组数。
每组数据的第一行包含三个整数N, M,K( 1<=N<=100, 0<=M<=1000, 1<=K<=N),分别代表参与表演的员工人数、画下的横线数目以及度度熊的员工编号。
每组数据的第2~M+1行每行包含3个整数, xl, xr, y, (1 <= xl < N, xr = xl + 1, 0 <= y <= 1,000,000),描述了一条横线的位置。
输出
对于每组数据输出一行Yes或者No,表示度度熊能否通过增加一条横线段来使得自己变成第一位出场表演。如果度度熊已经是第一位出场表演,也输出Yes。注意,尽管输入数据中员工画的横线高度都是整数,但是度度熊可以在任意实数高度画横线。此外,度度熊和员工一样,在画横线时需要避免在同一位置重复画线,也要避免两条相邻的横线连在一起。
样例输入
2
4 6 3
1 2 1
1 2 4
1 2 6
2 3 2
2 3 5
3 4 4
4 0 3
样例输出
Yes
No
代码1:/*
度度熊就是要第一个出场
* 程序未检测输入数据的合法性
*/
#include<iostream>
#include<map>
#include<vector>
#include<climits>
#include<string>
#include<set>
using namespace std;
int ComputeRank(map<int, map<double, int> > &line_map, int k)
{
// 判定是否已经是第一个出场
int num = k;
map<int, map<double, int> >::iterator iter = line_map.find(num);
if(iter==line_map.end())
{
return num;
}
double y = INT_MAX;
while(true)
{
map<double, int>::iterator iter2 = iter->second.begin();
for(; iter2!=iter->second.end(); ++iter2)
{
if(iter2->first < y)
{
break;
}
}
if(iter2!=iter->second.end())
{
y = iter2->first;
num = iter2->second;
}
else
{
return num;
}
iter = line_map.find(num);
}
return num;
}
bool CanBeFirst(map<int, map<double, int> > &line_map, int k, int n, set<double, greater<int> > &allY)
{
// 判定是否已经是第一个出场
int rank = ComputeRank(line_map, k);
if(rank == 1)
{
return true;
}
// 如果不是,则添加横线,再判断能否第一个出场
set<double, greater<int> >::iterator iterY = allY.begin();
double test = *iterY + 1;
do
{
if(k>1)
{
map<int, map<double, int> > tMap = line_map;
map<int, map<double, int> >::iterator tmpIter = tMap.find(k);
if(tmpIter == tMap.end())
{
map<double, int> tMap1;
tMap1.insert(make_pair(test, k-1) );
tMap.insert(make_pair(k, tMap1) );
}
else
{
tmpIter->second.insert(make_pair(test, k-1));
}
rank = ComputeRank(line_map, k);
if(rank == 1)
{
return true;
}
}
if(k<n)
{
map<int, map<double, int> > tMap = line_map;
map<int, map<double, int> >::iterator tmpIter = tMap.find(k);
if(tmpIter == tMap.end())
{
map<double, int> tMap1;
tMap1.insert(make_pair(test, k+1) );
tMap.insert(make_pair(k, tMap1) );
}
else
{
tmpIter->second.insert(make_pair(test, k+1));
}
rank = ComputeRank(line_map, k);
if(rank == 1)
{
return true;
}
}
if(iterY == allY.end())
{
break;
}
test = *iterY;
++iterY;
if(iterY == allY.end())
{
test -= 1;
}
else
{
test += *iterY;
test /=2;
}
}while(true);
return false;
}
int main(void)
{
int i , t , xl, xr, y , n , m , k;
cin>>t;
for(i = 0 ; i < t ; ++i)
{
// line_map存放(xl, (y,xr)) 和 (xr, (y,xl))
map<int, map<double, int> > line_map;
// allY存放各种可能的高度
set<double, greater<int> > allY;
cin>>n>>m>>k;
if(!m)
{
puts("No");
continue;
}
while(m--)
{
cin>>xl>>xr>>y;
allY.insert(y);
map<int, map<double, int> >::iterator iter;
iter=line_map.find(xl);
if(iter!=line_map.end())
{
iter->second.insert(make_pair(y, xr));
}
else
{
map<double, int> tmp;
tmp.insert(make_pair(y, xr));
line_map.insert(make_pair(xl, tmp) );
}
iter=line_map.find(xr);
if(iter!=line_map.end())
{
iter->second.insert(make_pair(y, xl));
}
else
{
map<double, int> tmp;
tmp.insert(make_pair(y, xl));
line_map.insert(make_pair(xr, tmp) );
}
}
if(CanBeFirst(line_map, k, m, allY) )
puts("Yes");
else
puts("No");
}
return 0;
}
代码2:/*
1、从下向上,找第一名的路径,把横线段做标记1,没有横线段的地方添加横线段出来,标记2
2、从上向下,找第k名(即度度熊的位置)的路径,遇到有标记的即表示本身就是第一(标记1),或加线段后可以是第一(标记2)
*/
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef struct line
{
int xl;
int xr;
int y;
int path;
}line;
//升序排序,是"<",降序排列是">"号
bool cmp(line a,line b)
{
return a.y<b.y;
}
int main(void)
{
int t , i , j , tag , n , m , k , max3 , noline;
cin>>t;
while (t--)
{
tag = max3 = noline = 0;//员工数,线段树,度度熊的位置
cin>>n>>m>>k;
int tmpK = k;
vector<line> array; //M条线段
line lin;
for(i = 0 ; i < m ; ++i)
{
cin>>lin.xl>>lin.xr>>lin.y;
lin.path = 0;
array.push_back(lin);
}
//按线段高低降序排列按线段高低降序排列
sort(array.begin(),array.end(),cmp);
//从下向上,找第一名的路线,线段path标记为1
int firstpath = 1;
int preelem3;
preelem3 = 0;
for(i = 0 ; i < m ; ++i)
{
max3 = max3 > array[i].y ? max3 : array[i].y;
if (array[i].xl==firstpath || array[i].xr==firstpath)
{
++noline;
//与上一个高度差
if(array[i].y > preelem3+1)
{
for (j = array[i].y-1 ; j > preelem3 ; --j)
{
lin.xl = firstpath;
lin.xr = firstpath+1;
lin.y = j;
lin.path = 2;
array.push_back(lin); //往右添加横线
lin.xl = firstpath-1;
lin.xr = firstpath;
array.push_back(lin); //往左添加横线
}
}
//主轴移动到旁边一个轴上
firstpath = array[i].xl==firstpath ? array[i].xr : array[i].xl;
array[i].path = 1;
preelem3 = array[i].y;
}
}
if(noline==0)
{
for(j = 0 ; j < max3 + 1 ; ++j)
{
lin.xl = 1;
lin.xr = 2;
lin.y = j;
lin.path = 2;
array.push_back(lin); //往右添加横线
}
}
//在主轴最大值上向左右加横线
for(i = preelem3 + 1 ; i <= max3+1 ; ++i)
{
lin.xl = firstpath;
lin.xr = firstpath+1;
lin.y = i;
lin.path = 2;
array.push_back(lin); //往右添加横线
lin.xl = firstpath-1;
lin.xr = firstpath;
array.push_back(lin); //往左添加横线
}
//稳定排序,使固有线段在后加线段之前
stable_sort(array.begin(),array.end(),cmp);
//从上向下,找度度熊的路线,看能否遇到有标记的线段
preelem3 = 1000000;
for (i = array.size()-1 ; i >= 0 ; --i)
{
if ( (array[i].xr!=preelem3) && (array[i].xl==tmpK || array[i].xr==tmpK) )
{
if (array[i].path>0)//线段标有1,表示度度熊本身就是第一; 是2表示可以通过加一个线段变为第一
{
tag++;
}
tmpK = array[i].xl == tmpK ? array[i].xr : array[i].xl;
preelem3 = array[i].y;
}
}
if(tag>0) //tag>0表示可以通过加线段改为第一,tag的值表示可添加线段的位置的个数
puts("Yes");
else
puts("No");
}
return 0;
}
/*
2
4 7 3
1 2 12
1 2 2
2 3 11
2 3 9
3 4 10
3 4 8
3 4 7
Yes
4 0 3
No
*/