H - 郭大侠与英雄学院
就是给你一个n*m的矩阵,然后叫你缩小这个矩阵,而且每行每列的数之间的大小关系不变,而且全为正数。
开始时想了好久也没想出来
先讨论没有重复点的情况,就是先把所有点按值升序排序,然后依次往新矩阵里放,放时的新的值为max(它所在行的最大值,它所在列的最大值)+1。然后这么放就行
但是有重复点,就比较麻烦了,而且只有同行同列的重复点才会产生影响,就是他们在新矩阵的值必须是一样的,如果不同行不同列,那么就没有影响
然后对于同行同列的相等的数,就必须用并查集把他们放到同一个集合里,
然后就是每行每列的扫过去就行,然后我是用set查的,遇到重复就并查集合并,那并查集用什么来编号呢,我是用的他们的位置,把二维转一维后按位置编号,这样编号就唯一啦,然后后面操作也方便
然后也是按值升序sort,然后从小到大往里面放数
还是考虑重复的情况,对于同一行同一列,相同数必须也要有对应的相同的新值,但是我们是按值的大小放的,所以所有相同的值会连续的放完,然后再放下一批相同的数,这样的话,我们就需要保存每行每列上的最大值,和这个最大值对应的之前的值的所在集合的根节点的那个编号,为什么要保存这个呢,首先要保存最大值是肯定的,然后因为考虑到相同的值是同一个集合嘛,所以要保存最大值所在集合的编号
然后后面更新的时候,如果发现当前值所在集合的编号和目前所在行/列的最大值的编号一样,就说明已经出现过了,不要再处理了,然后如果不一样的话,就是max(当前值所在集合的对应值,行最大值+1),然后再max(当前值所在集合的对应值,列最大值+1)。当然,我把所有数的初始对应值都设为0。
然后因为我们所有同一集合里的数必须有相同的新值,所以我们更新时更新的是这个数的根节点的对应值,
这样操作完之后,就该输出啦,输出时我们也是输出这个点的根节点的新值就好啦
end
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <set> using namespace std; #define ll long long #define maxn 1000005 int n, m; struct Node { int num, idx; void make(int n, int i) { num=n,idx=i; } bool operator <(Node x)const { return num < x.num; } bool operator ==(Node x)const { return num == x.num; } bool operator <=(Node x)const { return num <= x.num; } }grid[maxn], row[maxn], column[maxn]; int aim[maxn]; int parent[maxn]; int size[maxn];//结点数 void init_parent() { for (int i = 0; i<maxn; ++i) { parent[i] = i; size[i] = 1; } } int findparent(int x)//路径压缩 { if (x == parent[x]) return x; else return parent[x] = findparent(parent[x]); } void unionparent(int x, int y)//启发式合并 { int fx = findparent(x); int fy = findparent(y); if (fy == fx) return; if (size[fx] >= size[fy]) { size[fx] += size[fy]; parent[fy] = fx; } else { size[fy] += size[fx]; parent[fx] = fy; } } int main() { //freopen("input.txt", "r", stdin); scanf("%d%d", &n, &m); init_parent(); for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) { scanf("%d", &grid[i*m + j].num); grid[i*m + j].idx = i*m + j; } set<Node> tmp; set<Node>::iterator itor; for (int i = 0; i < n; ++i) { tmp.clear(); for (int j = 0; j < m; ++j) { itor = tmp.find(grid[i*m + j]); if (itor == tmp.end() || itor->num != grid[i*m + j].num) tmp.insert(grid[i*m + j]); else unionparent(itor->idx, grid[i*m + j].idx); } } for (int i = 0; i < m; ++i) { tmp.clear(); for (int j = 0; j < n; ++j) { itor = tmp.find(grid[j*m + i]); if (itor == tmp.end() || itor->num != grid[j* m + i].num) tmp.insert(grid[j*m + i]); else unionparent(itor->idx, grid[j*m + i].idx); } } /*for (int i = 0; i < n*m; ++i) printf("%d ", findparent(i)); printf("\n");*/ sort(grid, grid + n*m); /*for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) printf("%d %d\n", grid[i*m + j].num, grid[i*m + j].idx); } printf("\n");*/ for (int i = 0; i < n*m; ++i) row[i].idx = -1, column[i].idx = -1; for (int i = 0; i < n*m; ++i) { int idx = grid[i].idx; int pa = findparent(idx); if (row[idx/m].idx!=pa) aim[pa] = max(aim[pa], row[idx / m].num + 1); if (column[idx%m].idx != pa) aim[pa] = max(aim[pa], column[idx%m].num + 1); //row[idx / m] = max(row[idx / m], aim[pa]); row[idx / m].make(aim[pa], pa); column[idx%m].make(aim[pa], pa); //column[idx%m] = max(column[idx%m], aim[pa]); //printf("%d %d %d %d\n", pa, aim[pa], row[idx / m], column[idx%m]); } //printf("ans:\n"); for (int i = 0; i < n; ++i) { //printf("%d", aim[findparent(i*n)]); for (int j = 0; j < m; ++j) printf("%d ", aim[findparent(i*m + j)]); printf("\n"); } //system("pause"); //while (1); return 0; }