2014北京邀请赛 A:A Matrix 构造+贪心

题目连接: http://acm.bnu.edu.cn/bnuoj/problem.php?search=2014+ACM-ICPC+Beijing+Invitational+Programming+Contest

题解:显然,如果在第i行(i > 1)有一个数,那么这个数一定是被第i-1行一个比他小的数挤下来的

           那么就可以从最后一行开始不断往上找比他小的数, 直到第一行,形成一个个链,最后再从第一行开始把链一个个倒着输出出来就是答案了。

   如果有个数找不到链了那么说明无解

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<set>
using namespace std;

#define CLR(a,b) memset(a,b,sizeof(a))
const int N = 100000+20;
int n,m;
vector<int> a[N];
set<int> s[N];
set<int>::iterator ite;

int pre[N];
int nxt[N];
bool vis[N];
vector<int> ans;

bool work(int l,int num){
    if(l < 0)return 1;
    if(s[l].size() == 0)return 0;
    set<int>::iterator kte = s[l].lower_bound(num);
    if(kte == s[l].begin())return 0;
    kte--;
    pre[num] = *kte;
    nxt[*kte] = num;
    s[l].erase(kte);
    return 1;
    //return work(l-1, *kte);
}

void gao(int num)
{
    vector<int> tmp;
    while(nxt[num] != -1){
        vis[num] = 1;
        tmp.push_back(num);
        num = nxt[num];
    }
    vis[num] = 1;
    ans.push_back(num);
    for(int i = tmp.size() - 1 ;i >= 0; i --)ans.push_back(tmp[i]);
}

void solve()
{
    CLR(pre,-1);
    CLR(nxt,-1);
    CLR(vis,0);
    bool ok = 1;
    ans.clear();
    for(int i = m-1 ; i > 0 ; i --){
        for(int j = a[i].size()-1; j >= 0 ; j--){
            if(!work(i-1, a[i][j])){
                ok = 0;
                break;
            }
        }
        if(!ok)break;
    }
    if(!ok){
        puts("No solution");
    }else{
        for(int i = 0 ; i < m ; i ++){
            for(int j = 0 ;j < a[i].size(); j ++){
                if(!vis[a[i][j]]){
                    gao(a[i][j]);
                }
            }
        }
        for(int i = 0; i < ans.size() ; i ++){
            if(i > 0)printf(" ");
            printf("%d",ans[i]);
        }
        puts("");
    }
}

 int main()
 {
     int T,cas = 0;
     scanf("%d",&T);
     while(T--){
         cas ++;
         printf("Case #%d: ",cas);
         scanf("%d%d",&n,&m);
         for(int i = 0 ; i < m ; i ++)a[i].clear();
         for(int i = 0 ; i < m ; i ++){
             int num;
             scanf("%d",&num);
             while(num--){
                 int x;
                 scanf("%d",&x);
                 a[i].push_back(x);
             }
         }
         bool ok = 1;
         for(int i = 0 ; i < m ; i ++){
             for(int j = 1 ;j < a[i].size() ;j ++){
                 if(a[i][j] < a[i][j-1])ok = 0;
             }
         }
         for(int i = 0 ;i < m ;i ++){
             s[i].clear();
             for(int j = 0; j < a[i].size() ; j ++){
                 s[i].insert(a[i][j]);
             }
         }
         if(!ok){
             puts("No solution");
         }else{
             solve();
         }
     }
     return 0;
 }

 /*
 100
 7 3
 3 1 4 6
 3 2 5 7
 1 3
 */


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值