例题5-9 数据库(Database,ACM/ICPC NEERC 2009,UVa1592)题解

欢迎访问我的Uva题解目录哦 https://blog.****.net/richenyunqi/article/details/81149109

题目描述

例题5-9 数据库(Database,ACM/ICPC NEERC 2009,UVa1592)题解

题意解析

输入一个n行m列的数据库(1≤n≤10000,1≤i≤10),是否存在两个不同行r1,r2和两个不同列c1,c2,使得这两行和这两列相同(即(r1,c1)和(r2,c1)相同,(r1,c2)和(r2,c2)相同)。

算法设计

直接写一个四重循环枚举r1,r2,c1,c2肯定会超时,可以利用map来优化算法。以下算法涉及到的行号和列号均从0开始编号
先利用unordered_map<string,vector<int>>来存储每一列中哪些行字符串相同,其中键存储字符串,值存储行号。例如对于第一组输入数据:

0 1 2
0 How to compete in ACM ICPC Peter [email protected]
1 How to win ACM ICPC Michael [email protected]
2 Notes from ACM ICPC champion Michael [email protected]

第1列中1、2行字符串相同,在unordered_map<string,vector<int>>存储形式为{"Michael",{1,2}}
共有m列,所以可以定义vector<unordered_map<string,vector<int>>>columns(m)来存储每一列的信息。
接着定义一个map<pair<int,int>,int>rows,具体使用方法是:遍历整个columns,针对第一组输入数据,遍历到columns[1]时,columns[1]中含有元素{"Michael",{1,2}},以columns[1]的值{1,2}作键,以列号1作值,将{{1,2},1(这里的1指的是列号)}放入rows中。接着遍历到columns[2]时,columns[2]含有元素{"[email protected]",{1,2}},而rows中已经有{1,2}这个键了,我们便找到了满足要求的r1,r2,c1,c2,即1,2,1,2(这里的行号列号均由0开始,输出时都要加1)

C++代码

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m;
    while(~scanf("%d%d%*c",&n,&m)){
        string line;
        vector<unordered_map<string,vector<int>>>columns(m);
        for(int i=0;i<n;++i){
            getline(cin,line);
            string s="";
            for(int j=0,k=0;j<=line.size();++j)//j用来分割字符串,k表示列号
                if(j==line.size()||line[j]==','){//遇到字符串末尾或,表示一个字符串分割完毕
                    columns[k++][s].push_back(i);
                    s="";
                }else
                    s+=line[j];
        }
        map<pair<int,int>,int>rows;
        for(int i=0;i<columns.size();++i)//遍历columns
            for(auto&j:columns[i])//对于columns[i]中的每个元素
                if(j.second.size()>1){//该列中字符串出现次数超过1次,即至少有两行字符串相同
                    for(int k1=0;k1<j.second.size();++k1)//遍历行号
                        for(int k2=k1+1;k2<j.second.size();++k2){//遍历行号
                            pair<int,int>p=make_pair(j.second[k1],j.second[k2]);
                            if(rows.find(p)!=rows.end()){
                                printf("NO\n%d %d\n%d %d\n",p.first+1,p.second+1,rows[p]+1,i+1);
                                goto loop;
                            }else
                                rows.insert({p,i});
                        }
                }
        puts("YES");
        loop:;
    }
    return 0;
}