例题5-9 UVA1592 Database(35行AC代码)

紫书刷题进行中,题解系列【GitHub|CSDN

例题5-9 UVA1592 Database(35行AC代码)

题目大意

给出n*m的表格,判断是否存在两行,他们对应存在两列相同元素,即(r1,c1)=(r2,c1);(r1,c2)=(r2,c2)

思路分析

暴力枚举任意两行两列时间复杂度O(n^4),会超时。因此进行如下优化设计:

枚举任意两列c1,c2,对于这两列,遍历每一行,将两列中的元素用二元组记录,存于map中,若后需遍历发现重复二元组,则表示找到结果,其时间复杂度为O(m*m*n*logn)

若直接用map存储字符串,效率低下,可手动给每个字符串分配编号,map中只需存放其编号即可(二级索引)

map<string, int> idmp; // 字符串->id
vector<int> table[n+1]; // 表中存放字符串对应的id

同时,为了便于输出目标对应的行号,定义如下映射(将二元组置于key是便于查找)

map<pair<int,int>, int> pos; // 两列对应字符串标号->行
  • 可用stringstream与getline实现以,分割字符串
getline(cin, s); stringstream input(s); // 字符串流
while (getline(input, st, ',')) table[i].push_back(getId(st));

AC代码(C++11,map优化,行列同素求解)

#include<bits/stdc++.h>
using namespace std;
int n, m;
string s, st;
map<string, int> idmp; // 字符串->id
int getId(string s) { // 获取字符串id,若已存在,直接返回,否则分配id
    if (idmp.find(s) == idmp.end()) idmp.insert({s, idmp.size()}); // 不存在
    return idmp[s];
}
int main() {
    while (cin >>n >>m) {
        getchar(); vector<int> table[n+1]; idmp.clear(); // 初始化!!!
        for (int i = 0; i < n; i ++) {
            getline(cin, s); stringstream input(s);
            while (getline(input, st, ',')) table[i].push_back(getId(st));
        }
        bool isPNF = true; // 标记是否为PNF
        for (int i = 0; i < m-1 && isPNF; i ++) { // 遍历任意两列
            for (int j = i+1; j < m && isPNF; j ++) {
                map<pair<int,int>, int> pos; // 两列对应字符串标号->行
                for (int k = 0; k < n && isPNF; k ++) { // 每一行
                    if (pos.find({table[k][i],table[k][j]}) == pos.end()) {
                        pos[{table[k][i],table[k][j]}] = k;
                    }
                    else {
                        printf("NO\n%d %d\n%d %d\n", pos[{table[k][i],table[k][j]}]+1, k+1, i+1, j+1);
                        isPNF = false;
                    }
                }
            }
        }
        if (isPNF) printf("YES\n");
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值