【刘汝佳书】例题5-9 UVA1592(关于编号和map判重)

【2019.4.5】
这道题看了书上思路才写出来
从uDebug中的测例可以看出,代码是需要按列枚举的:先从第1列和第2列开始,枚举每一行,把这一行的第1列和第2列的元素组成二元组,记录其出现的行数,放到map里,看是否有重复的二元组
如果找到重复二元组,直接跳出所有循环,输出NO
如果没找到,就再枚举第1列和第3列,直到枚举完所有列,输出YES

map的结构:<<二元组>,<行数>>
<二元组>:<i行j列的字符串,i行k列的字符串>
<行数>:<i>

那么现在问题变成了:如何把两个字符串组成二元组放到map的key里?
我们可以分两步来做:

1、首先将一个字符串转化成一个int整数
将【复杂数据类型】转换成【int】的一大方法就是编号(ID),用map<复杂数据类型, int>来提供一一映射。
比如这道题,是把字符串string转换成int
比如【刘汝佳书】例题5-5 UVA12096这道题,是把集合set转换为int
无外乎就是写一个int getID(string s)子函数,当map中有s时,返回其ID,没有时,先插入到map中,并根据map.size()返回其ID

2、其次将两个int整数转化成二元组
突然想起来这道电子表格的题【刘汝佳书】例题4-5 UVA512
这道题里面用了一个方法:用一个整数index = i*10000 + j来表示一个位置的格子(i,j)
其中10000是个比较大的数字,保证index不会重复
在本题中,我们也可以用这样的方法,把两个int整数转化成一个整数
本题最多有10000行,10列,10^6个元素
因此,假设两个字符串的序号分别为ij,我们可以用index = i*100000 + j来表示ij组成的二元组,其中indexlong long型的
此时,map结构变成:

map的结构:<long long, int>
long long:第i行中,j列和k列的字符串组成的二元组
int:行数,i

代码如下:

#include <iostream>
#include <map>
#include <string>
#include <vector>

using namespace std;

vector<vector<string>> table;	//存表
map<long long, int> mi;    		//字符串对-行号
map<string, int> ID;			//字符串-ID

//获取字符串s的ID
//如果已经在ID表中,返回
//如果没有,分配一个新ID,插入ID表
int getID(string s) {
    if(ID.count(s)) return ID[s];
    else {
        int i=ID.size();
        ID[s] = i;
        return i;
    }
}

int main()
{
    //freopen("C:\\Users\\Summer\\Desktop\\input.txt", "r", stdin);
    //freopen("C:\\Users\\Summer\\Desktop\\output.txt", "w", stdout);

    int n, m;
    string s;
    char c;
    bool isPNF;
    while(cin>>n>>m) {
        //初始化
        table.clear();
        mi.clear();
        isPNF = true;

        //输入
        getchar();	//第一行输入最后的换行符
        for(int i=0; i<n; i++) {
            table.push_back(vector<string>());
            for(int j=0; j<m; j++) {
            	//获取一个格子中的字符串,遇到EOF、逗号、换行停止
                s = "";
                while((c = getchar())!=EOF && c!=',' && c!='\n') {
                    s += c;
                }
                table[i].push_back(s);
            }
        }

        //遍历每两列c1,c2
        int r1, r2;
        int c1, c2;
        for(c1 = 0; c1 < m; c1++) {
            for(c2 = c1+1; c2 < m; c2++) {
                mi.clear();
                //对于每一行i
                for(int i=0; i<n; i++) {
                	//分别获取i行c1列和c2列的字符串ID
                    int id1 = getID(table[i][c1]);
                    int id2 = getID(table[i][c2]);
                    //如果这个二元组已经在表内,证明重复,直接退出
                    if(mi.count(id1*100000+id2)) {
                            isPNF = false;
                            r1 = mi[id1*100000+id2];
                            r2 = i;
                            break;
                    }
                    //如果二元组不在表内,就插入表内
                    else{
                        mi[id1*100000+id2] = i;
                    }
                }
                if(!isPNF) break;
            }
            if(!isPNF) break;
        }

        //输出
        if(!isPNF) {
            cout<<"NO"<<endl;
            printf("%d %d\n%d %d\n", r1+1, r2+1, c1+1, c2+1);
        }
        else cout<<"YES"<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41727666/article/details/89040489