您的位置:首页 > 其它

Codeforces Round #345 (Div. 2) E. Table Compression(并查集)★ ★

2016-09-07 20:49 218 查看
题意:给你n*m的矩阵,叫你转化成为另外一个矩阵,使得矩阵中的数字之和最小,且同一行,同一列的两个数的关系仍和原来的矩阵相同。

 

思路:因为同一行同一列的两个数仍要满足原来的等价关系,所以就相当于暗含了一个拓扑序,

那么同一行和同一列的数相同的数要怎么办呢?利用一个并查集把他们捆绑起来。(先对原来的序列进行一个排序)

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF  0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-9
#define maxn 1000100
#define MOD 1000000007

int f[maxn],rx[maxn],ry[maxn];
int ans[maxn],pre_rx[maxn],pre_ry[maxn];
struct node
{
int num,x,y;
} mp[maxn];

int find(int x)
{
while(x != f[x])
x = f[x] = f[f[x]];
return f[x];
}

void merge(int x,int y)
{
int xx = find(x),yy = find(y);
if(xx != yy)
f[yy] = xx;
}

bool cmp(node x,node y)
{
return x.num < y.num;
}

int main()
{
int n,m;
scanf("%d%d",&n,&m);
int cnt = 1;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
scanf("%d",&mp[(i-1)*m+j]);
mp[cnt].x = i,mp[cnt++].y = j;
f[(i-1)*m+j] = (i-1)*m + j;
}
sort(mp+1,mp+n*m+1,cmp);
int k;
for(int i = 1; i <= n*m; i = k)
{
for(k = i+1; k <= n*m && mp[k].num == mp[i].num; k++);
for(int j = i; j < k; j++)
{
int x = mp[j].x,y = mp[j].y;
if(!rx[x])
rx[x] = (x-1)*m + y;
else
merge(rx[x],(x-1)*m+y);
if(!ry[y])
ry[y] = (x-1)*m+y;
else
merge(ry[y],(x-1)*m+y);
}
for(int j = i; j < k; j++)
{
int x = mp[j].x,y = mp[j].y,r = find((x-1)*m+y);
ans[r] = max(ans[r],max(pre_rx[x],pre_ry[y])+1);
}
for(int j = i; j < k; j++)
{
int x = mp[j].x,y = mp[j].y,r = find((x-1)*m+y);
ans[(x-1)*m+y] = ans[r];
pre_rx[x] = pre_ry[y] = ans[r];
rx[x] = 0,ry[y] = 0;
}
}
for(int i = 1; i <= n*m; i++)
{
if(i%m == 0)
printf("%d\n",ans[i]);
else
printf("%d ",ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: