例题5-9 数据库

题目链接:UVaoj 1592 Database

UVa1592
题目翻译:

对于一个数据库表,如果仅当没有任意两行对应的任意两列数据相同时,表才为PNF格式。
输入:
输入包含多个实例。每个实例的第一行包含两个整数n和m(1≤n≤10000,1≤m≤10),即表中的行数和列数。以下n行包含表行。每行有m个列值,用逗号分隔。列值由从空格(ASCII代码32)到~(ASCII代码126)的ASCII字符组成,逗号(ASCII代码44)除外。值不为空,并且没有前导和尾随空格。每行最多有80个字符(包括分隔逗号)。
输出:
对于每个实例,如果该表是PNF格式,则输出一个单词“yes”(不带引号)。如果该表不是PNF格式,则输出三行。在第一行输出一个单词“no”(不带引号)。在第二行输出两个整数行数r1和r2(1≤r1,r2≤n,r1≠r2),在第三行写两个整数列数c1和c2(1≤c1,c2≤m,c1≠c2),使c1和c2列中的值在第r1和r2行中相同。

思路:

本题的目的是检查数据表中不同的二行,对应二列字符串是否相同:
1.储存数据库:根据题目得知这个数据库最大为10000×10,需要定义一个二维数组储存
2.查找数据库:如果直接四重循环枚举r1,r2,c1,c2最终会超时;可以定义一个map(键为数据表的数据,值为行r),然后枚举每两列c1和c2,然后从上到下扫描各行。每次碰到一个新的行r ,把(r1,c1),(r1,c2)的数据作为一个二元组到map中查找键值。如果map的键值中已经存在这个二元组,该二元组映射到的就是所要求的r1,而当前行就是r2。如果没找到就把(r1,c1),(r1,c2)的数据作为一个二元组(键)和新行r(值)添加到这个map中。
3.优化查找:给每个数据编号(ID),定义一个map(键为数据表的数据,值为编号),对于每一个输入数据首先查找它是否在这个map键值中,如果有则返回它的值(编号),没有则将数据(键)和编号(值)添加到map中(编号初始化为0,每次插入编号++)。
4.数据读取:读取整行存储到string型变量中,再查找逗号位置,通过逗号位置和字符串长度进行数据截取。

新知识:

1.上面( 将(r1,c1),(r1,c2)的数据作为一个二元组)使用的是pair类型
pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同

#include
pair p1;//创建一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化。
pair p1(v1, v2);//创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2。
make_pair(v1, v2);          // 以v1和v2的值创建一个新的pair对象,其元素类型分别是v1和v2的类型。
p1.first;                   // 返回对象p1中名为first的公有数据成员
p1.second;                 // 返回对象p1中名为second的公有数据成员
//pair类型的使用相当的繁琐,如果定义多个相同的pair类型对象,可以使用typedef简化声明:
typedef pair two;
two a=make_pair (1,2);

2.string的查找和截取

/*string查找:find*/
string s1(“dog bird chicken bird cat”) ; 
string s2 = s.find('i',6) ; // 从下标为6开始找字符 'i',返回找到的第一个i的下标
 cout << s2<< endl ; // 结果:11
/*string截取字符串:substr*/
string s1(“123456789") ;
string s2 = s1.substr(3,4) ; //从下标为3开始截取4个字符
cout<

3.map的添加和查找

/*用数组方式插入数据*/
m[key]=value;

/*查找: */
m.count(key)
//返回的是被查找元素的个数。map中不存在相同键值,所以返回值只能是1或0。
代码:
#include
#include
#include
#include
#include
#include
using namespace std;

typedef pair PII;

const int maxr = 10000 + 5;
const int maxc = 10 + 5;

int m, n, db[maxr][maxc], cnt;//db为数据库;cnt为字符串编号

map id;
int ID(const string& s) {
    if (!id.count(s)) {
        id[s] = ++cnt;
    }
    return id[s];
}

void find() {
    for (int c1 = 0; c1 < m; c1++)
        for (int c2 = c1 + 1; c2 < m; c2++) {
            map d;
            for (int i = 0; i < n; i++) {
                PII p = make_pair(db[i][c1], db[i][c2]);//(r,c1),(r,c2)的数据合成一个二元组
                if (d.count(p)) {    //如果被找到
                    printf("NO\n");
                    printf("%d %d\n", d[p] + 1, i + 1);
                    printf("%d %d\n", c1 + 1, c2 + 1);
                    return;
                }
                d[p] = i;//添加到d中。
            }
        }
    printf("YES\n");
}

int main() {
    string s;
    while (getline(cin, s)) {
        stringstream ss(s);
        if (!(ss >> n >> m)) break;
        cnt = 0;            //编号初始化为0
        id.clear();     //将id清空(初始化)
        for (int i = 0; i < n; i++) {
            getline(cin, s);
            int lastpos = -1;//定义逗号在最前
            for (int j = 0; j < m; j++) {
                int p = s.find(',', lastpos + 1);
                if (p == string::npos) p = s.length();      // 如果没找到逗号,逗号就在最后面。string::npos是个返回值,相当于-1
                db[i][j] = ID(s.substr(lastpos + 1, p - (lastpos + 1)));//截取两个逗号间的数据
                lastpos = p;
            }
        }
        find();
    }
    return 0;
}

你可能感兴趣的:(例题5-9 数据库)