题目大意:
现在一共有n张多米诺卡牌,每张卡牌都是两个点数相连,现在要求将这些卡牌摆放之后能够满足:
1.靠左边的点数从上到下成不减序列
2.靠右边的点数从上到下成不增序列
问是否存在这样的摆法,存在则输出一行“YES”后输出一组摆法,否则输出“NO”
大致思路:
首先要明白,对于含有最小数字的那张多米诺牌一定可以将最小点数放在最左上方作为第一张牌,理由是:
最小的点数一定是出现在最左上角或最右下角
然而对于一组满足条件的摆法,将整个排列图形180度旋转之后必然也满足条件(两边是相反的单调性)
那么一旦有解,最小的那张放在第一个一定能行
对于一组n张给定的多米诺卡牌,每张卡牌都有两种状态,那么将每张卡牌的两种状态都考虑进来
这样得到2*n张的一组牌,将它们按第一个数字升序排列,遇到相同的则按第二个数字降序排列
然后再得到的序列中进行遍历,每次遇到可以加入的卡牌就加入,然后记录当前卡牌已经用过,其下一种状态不予考虑,那么,在遍历一遍之后看加入的卡牌总数,
如果加入的卡牌张数是n则可行,输出方案
若不是n则不可行,这个是可以证明的,你可以假设对立的情况然后反证
代码如下:
Result : Accepted Memory : 6617 KB Time : 187 ms
/*
* Author: Gatevin
* Created Time: 2014/7/25 14:32:11
* File Name: test.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define maxn 1000100
struct Node
{
int a,b,order;
};
Node node[2*maxn];
bool vis[2*maxn];
bool used[2*maxn];
int n;
bool cmp(const Node& n1, const Node& n2)
{
if(n1.a == n2.a)
{
return n1.b > n2.b;
}
else
{
return n1.a < n2.a;
}
}
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
scanf("%d %d", &node[i].a, &node[i].b);
node[i + n].a = node[i].b;
node[i + n].b = node[i].a;
node[i].order = node[i + n].order = i;
}
memset(vis, 0, sizeof(vis));
memset(used, 0,sizeof(used));
sort(node + 1, node + 1 + 2*n, cmp);
vis[1] = 1;
used[node[1].order] = 1;
int cnt = node[1].b;
int answer = 1;
for(int i = 2; i <= 2*n; i++)
{
if(!used[node[i].order] && cnt >= node[i].b)
{
answer++;
vis[i] = 1;
used[node[i].order] = 1;
cnt = node[i].b;
}
}
if(answer != n)
{
printf("NO\n");
}
else
{
printf("YES\n");
for(int i = 1; i <= 2*n; i++)
{
if(vis[i])
{
printf("%d %d\n", node[i].a, node[i].b);
}
}
}
return 0;
}