codeforces 274 D lovely matrix

Lenny had an n × m matrix of positive integers. He loved the matrix so much, because each row of the matrix was sorted in non-decreasing order. For the same reason he calls such matrices of integers lovely.

One day when Lenny was at school his little brother was playing with Lenny’s matrix in his room. He erased some of the entries of the matrix and changed the order of some of its columns. When Lenny got back home he was very upset. Now Lenny wants to recover his matrix.

Help him to find an order for the columns of the matrix so that it’s possible to fill in the erased entries of the matrix to achieve a lovely matrix again. Note, that you can fill the erased entries of the matrix with any integers.

Input
The first line of the input contains two positive integers n and m (1 ≤ n·m ≤ 105). Each of the next n lines contains m space-separated integers representing the matrix. An integer -1 shows an erased entry of the matrix. All other integers (each of them is between 0 and 109 inclusive) represent filled entries.

Output
If there exists no possible reordering of the columns print -1. Otherwise the output should contain m integers p1, p2, …, pm showing the sought permutation of columns. So, the first column of the lovely matrix will be p1-th column of the initial matrix, the second column of the lovely matrix will be p2-th column of the initial matrix and so on.

Examples
Input
3 3
1 -1 -1
1 2 1
2 -1 1
Output
3 1 2
Input
2 3
1 2 2
2 5 4
Output
1 3 2
Input
2 3
1 2 3
3 2 1
Output
-1

题意:

给一个矩阵,有些位置是空的,有些位置有数字。列之间的位置可以互换,要求一个交换后的矩阵使每一行的数字都非严格递增。

思路:

这题乍一眼看,好像和NOIP车站分级很像,应该是拓扑排序。

首先简化一下问题,如果保证一行里每个数distinct,那么只要把每一行排序,空格不管,排序后相邻的两个列之间连边,最后跑一遍拓扑排序,所得到的序列即答案,如果有环,就无解。

但是不保证每个数都不相同。最暴力的想法是对每一个数值相同的列都和相邻的连边,但是这样做空间和时间复杂度变成了 O ( m 2 ) ,过不了1e5的数据。所以我只好看题解了。所以可以使用“冗余点”的方法来解决数值相同的情况。如下图,非常巧妙。但据说是网络流的非常基本的操作。

这里写图片描述

下面贴代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1e5+10;
int n, m, a[N], b[N], cnt;
struct EDGE{
    int nxt, v;
}edge[N<<2];
int point[N<<1], e, indgr[N<<1];
queue<int> q;
int topo[N], nn;

bool cmp(int x, int y)
{
    return a[x] < a[y];
}

void add_edge(int u, int v)
{
    edge[++e] = (EDGE){point[u], v};
    point[u] = e;
}

int main()
{
    scanf("%d%d", &n, &m);
    cnt = 0;
    memset(point, -1, sizeof(point)); e = 0;
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++)
            scanf("%d", &a[j]), b[j] = j;
        sort(b+1, b+m+1, cmp);
        for (int j = 1; j <= m; j++){
            if (a[b[j]] == -1) continue;
            if (j == 1 || a[b[j]] != a[b[j-1]]) cnt++;
            add_edge(m+cnt, b[j]);
            add_edge(b[j], m+cnt+1);
            indgr[b[j]]++;
            indgr[m+cnt+1]++;
        }
        cnt++;
    }
    for (int i = 1; i <= m+cnt+1; i++)
        if (indgr[i] == 0)
            q.push(i);
    nn = 0;
    while (!q.empty()){
        int u = q.front(); q.pop();
        if (u <= m) topo[++nn] = u;
        for (int i = point[u]; i != -1; i = edge[i].nxt){
            int v = edge[i].v;
            indgr[v]--;
            if (indgr[v] == 0) q.push(v);
        }
    }
    if (nn < m) printf("-1");
    else
        for (int i = 1; i <= m; i++)
            printf("%d ", topo[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyyxyyx/article/details/82106745