URAL 1743 Domino Sorting 排序 + 贪心

题目大意:

现在一共有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;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值