poj 3865 数据库冗余问题判断

问题:给定由1-n索引的两列数据,问是否存在两行的某两列列值完全相同,即k1.c1 = k2.c1且k1.c2 = k2.c2

办法1:对第一列排序(o(nlogn)),找到第一列中列值相同的(mi个)在第二列中根据相应索引取出所有值并排序(o(milogmi)),顺序找出值相同的(mi)。总时间复杂度为o(nlogn+∑(mi+milogmi+mi))=o(nlogn+2n+∑milogmi)=o(2nlogn)

办法2:对两列带上索引都排序(o(nlogn)),对每列的每个键值找出与它列值相同但键值最小的f[i]保存(o(n)).设一个标志数组tag[N],第一列中列值相同的,第二列根据键值得到f[i],判断tag[f[i]]是否被标记,如果被标记表示之前已经有相同的出现,找到这样的两行他们的这两列值相同,否则标记tag[f[i]]。每次处理完列值相同的一组数据m个,对tag恢复默认,即把修改过的m个重新恢复。总复杂度o(2nlogn+n*3).

http://poj.org/problem?id=3865

此题中含有m列,判断冗余,比如下标中2,3行的2,3列

How to compete in ACM ICPCPeterpeter@neerc.ifmo.ruHow to win ACM ICPCMichaelmichael@neerc.ifmo.ruNotes from ACM ICPC championMichaelmichael@neerc.ifmo.ru

方法1超时:复杂度为o(m*nlogn)+C(m,2)*(2n+∑milogmi)=o(mnlogn+mmn+mmnlogn)=o(mmnlogn)

方法2勉强:复杂度o(m*nlogn+C(m,2)*n*3)=o(mnlogn+mmn)

上面把字符串的比较操作看作了1,此时m=10,n=10000,复杂度就是1为千万级,2为百万级。如果加上字符串比较操作可能还更长。如此看来2的复杂度比1低,表明处理两列时候1,2差不多,多列时候2更好。不知道还有什么好办法吗?

 

附方法2的计算代码:

struct Node
{
    char s[LEN];
    short row;
}node[M][N];  //M为列数,n为行数,row为初始给定的行号

void compute()
{
    int i,j,k,u,l;
    memset(tag,-1,sizeof(tag));
    for(i = m-1;i >= 0;i --){
        sort(node[i],node[i]+n,cmp);
        f[i][node[i][0].row] = node[i][0].row;
        for(j = 1;j < n;j ++)
        {
            if(strcmp(node[i][j].s,node[i][j-1].s) == 0)
                f[i][node[i][j].row] = f[i][node[i][j-1].row];
            else
                f[i][node[i][j].row] = node[i][j].row;
        }
        for(j = i+1;j < m;j ++)
        {
            tag[f[i][node[j][0].row]] = node[j][0].row;
            l = 0;
            for(k = 1;k <= n;k ++)
            {
                if(strcmp(node[j][k].s,node[j][k-1].s) == 0)
                {
                    if(tag[f[i][node[j][k].row]] != -1)
                    {
                        r1 = tag[f[i][node[j][k].row]]+1;
                        r2 = node[j][k].row+1;
                        c1 = j+1;
                        c2 = i+1;
                        return;
                    }
                    tag[f[i][node[j][k].row]] = node[j][k].row;
                }
                else{
                    for(u = k-1;u >= l;u --)
                        tag[f[i][node[j][u].row]] = -1;
                    tag[f[i][node[j][k].row]] = node[j][k].row;
                    l = k;
                }
            }
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值