2019牛客国庆集训派对day1 G

Problem

G-字典序_2019牛客国庆集训派对day1

Solution

题目让你求的是,把原来的列数重新排位置,能够得到非递减字典序的序列。输出的是该位置安排的是原来的第几列,并且使你输出的内容是所有符合输出里面的最小字典序。
如样例一:
4 3
4 3 3
1 5 1
1 5 1
3 5 2
答案为
2 1 3
重新排位置后得到的序列为:
3 4 3
5 1 1
5 1 1
5 3 2
每一行都比上一行的字典序要大,符合该题的两种排序为2 1 3和2 3 1,选择字典序小的2 1 3输出。
解决方案为:从0~(m-1)列寻找没有递减对的列数,找到后从0~(n-1)行进行遍历,如果在当前的列数时,该行比上一行大,那么后面的所有递减对都不造成影响,把后面的递减对记录删除,不断寻找没有递减对的列数。
如已排好的序列:
3 7 1
5 4 9
5 6 2
6 2 7
6 4 2
尽管在第二列有7 4和6 2两对递减对,但是因为先前已经选出3 5和5 6,后续递减对不造成影响,和数字大小627>562是同一个道理。

Code

#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 2000+5;
int n,m,arr[maxn][maxn],desc_num[maxn],ans[maxn];
bool vis[maxn],desc_allow[maxn];
int main() {
    while(cin >> n >> m) {
        memset(desc_num,0,sizeof(desc_num));
        memset(desc_allow,0,sizeof(desc_allow));
        memset(vis,0,sizeof(vis));
        for(int i=0; i<n; i++) {
            for(int j=0; j<m; j++) {
                cin >> arr[i][j];
                if(i && arr[i][j] < arr[i-1][j]) {
                    desc_num[j]++;  //记录第j列有n个递减对
                }
            }
        }
        bool flag = false;
        for(int i=0; i<m; i++) {
            int res = 0;
            for(int j=0; j<m; j++) {
                res = j;
                if(vis[j]) {
                    res++;
                    continue;
                }
                if(!desc_num[j]) {
                    break;
                }
                if(j == m-1) {
                    res++;
                }
            }
            if(res == m) {
                flag = true;
                break;
            }
            ans[i] = res;
            vis[res] = true;
            for(int j=1; j<n; j++) {
                if(desc_allow[j] || arr[j][res] <= arr[j-1][res]) {
                    continue;
                } else {
                    desc_allow[j] = true;  //记录第j和j-1行的后续的列里面允许有递减对
                    for(int k=0; k<m; k++) {
                        if(vis[k]) {
                            continue;
                        }
                        if(arr[j][k] < arr[j-1][k]) {
                            desc_num[k]--;  //第j行和第j-1行的后续递减对不影响字典序大小
                        }
                    }
                }
            }
        }
        if(flag) {
            puts("-1");
        } else {
            for(int i=0; i<m; i++) {
                if(i != m-1) {
                    cout << ans[i]+1 << " ";
                } else {
                    cout << ans[i]+1 << endl;
                }
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值