Peter studies the theory of relational databases. Table in the relational database consists of values thatare arranged in rows and columns.
There are different normal forms that database may adhere to. Normal forms are designed tominimize the redundancy of data in the database. For example, a database table for a library mighthave a row for each book and columns for book name, book author, and author’s email.
If the same author wrote several books, then this representation is clearly redundant. To formallydefine this kind of redundancy Peter has introduced his own normal form. A table is in Peter’s NormalForm (PNF) if and only if there is no pair of rows and a pair of columns such that the values in thecorresponding columns are the same for both rows.
How to compete in ACM ICPC |
Peter |
peter@neerc.ifmo.ru |
How to win ACM ICPC |
Michael |
michael@neerc.ifmo.ru |
Notes from ACM ICPC champion |
Michael |
michael@neerc.ifmo.ru |
The above table is clearly not in PNF, since values for 2rd and 3rd columns repeat in 2nd and3rd rows. However, if we introduce unique author identifier and split this table into two tables — onecontaining book name and author id, and the other containing book id, author name, and author email,then both resulting tables will be in PNF.
How to compete in ACM ICPC |
1 |
How to win ACM ICPC |
2 |
Notes from ACM ICPC champion |
2 |
1 |
Peter |
peter@neerc.ifmo.ru |
2 |
Michael |
michael@neerc.ifmo.ru |
Given a table your task is to figure out whether it is in PNF or not.
Input
Input contains several datasets. The first line of each dataset contains two integer numbers n and m(1 ≤ n ≤ 10000,1 ≤ m ≤ 10), the number of rows and columns in the table. The following n linescontain table rows. Each row has m column values separated by commas. Column values consist ofASCII characters from space (ASCII code 32) to tilde (ASCII code 126) with the exception of comma(ASCII code 44). Values are not empty and have no leading and trailing spaces. Each row has at most80 characters (including separating commas).
Output
For each dataset, if the table is in PNF write to the output file a single word “YES” (without quotes).If the table is not in PNF, then write three lines. On the first line write a single word “NO” (withoutquotes). On the second line write two integer row numbers r1 and r2 (1 ≤ r1,r2 ≤ n,r1 ̸= r2), onthe third line write two integer column numbers c1 and c2 (1 ≤ c1,c2 ≤ m,c1 ̸= c2), so that values incolumns c1 and c2 are the same in rows r1 and r2.
Sample Input
3 3
How to compete in ACM ICPC,Peter,peter@neerc.ifmo.ru
How to win ACM ICPC,Michael,michael@neerc.ifmo.ru
Notes from ACM ICPC champion,Michael,michael@neerc.ifmo.ru23
1,Peter,peter@neerc.ifmo.ru2,Michael,michael@neerc.ifmo.ru
Sample Output
NO
2 3
2 3
YES
本题分析:
- 我的天呐好难......最先碰到的问题就是,给出的Sample Input是字符串,中间有逗号...这可怎么分析啊...怎么存呢?接着想到,可以读入一个字符存一个字符,碰到","的话就分组。注意要把输入n和m之后的那个空行键给吃掉,不然的话读入会出问题。
- 将字符串都存好之后,下一步是啥...我的想法是循环求解。
- 肯定最naive的想法是对每一层的每一列都进行循环遍历。由于题目中说了,是两个不同的行和两个不同的列所以说四重循环......硬杠肯定会超时的少年......
- 接着想到了,哇哦可以用map映射!然而怎么映射呢咩......
- lrj大大给出了解决方法:只列举c1和c2,然后从上到下扫描各行。 每碰到一个新的行r,将c1,c2两列的内容作为一个二元组存到一个map中,如果map的键值中已经存在这个二元组,那么它映射的就是所要求的r1,当前的行就是r2。
- 哇哦!!!好主意耶!!!!
- 。。。。。。我的天。。。。。。放弃。。。我怎么想都还是四重循环。。。。。。回来再说。
代码如下:
#include<iostream>
#include<cstdio>
#include<map>
#include<string>
#include<vector>
using namespace std;
const int ROW = 10000 + 10;
const int COL = 10 + 5;
int n, m;
map<string, int> IDcache;//有没有很相似的赶脚......Uva12096书上的代码,熟悉的配方,熟悉的味道~但是为啥我想不到啊啊啊啊
vector<string> Strcache;
vector<int> Text[ROW];//保存处理后的文本,每个字符串都替换成一个编号
struct node
{
int x,y;
node(int x, int y):x(x), y(y) {}
bool operator < (const node& r) const { return x < r.x || x == r.x && y < r.y; }
};
map<node, int> data;
//查找给定集合的ID。如果找不到,那么分配一个新的ID。这里分配一个新的ID非常的重要。
int ID_alloc(string str)
{
if(IDcache.count(str))
return IDcache[str];
Strcache.push_back(str);
return IDcache[str] = Strcache.size() - 1;
}
void read()
{
string str;
char ch = getchar();//吃掉n和m之后的那个空格
for(int i = 0; i < n; i++)
{
for(; ;)
{
ch = getchar();
if(ch == '\n' || ch == '\r')
{
if(!str.empty())
Text[i].push_back(ID_alloc(str));//如果非空的话,那么就将str所代表的ID放到Text中,这里这种做法非常巧妙,它首先将读入的一个又一个字符串分别标上号,这样子的话接下来就可以直接映射map。lrj大大在书里面讲过......
str.clear();
break;
}
if(ch != ',')
str += ch;
else
{
Text[i].push_back(ID_alloc(str));
str.clear();
}
}
}
}
void solve()
{
int x, y, c1, c2;
for(c1 = 0; c1 < m; c1++)
{
for(c2 = c1 + 1; c2 < m; c2++)
{
data.clear();
for(int r = 0; r < n; r++)
{
x = Text[r][c1];
y = Text[r][c2];
node p(x, y);//映射map
if(!data.count(p))
data[p] = r;
else
{
cout << "NO" << endl;
cout << data[p] + 1 << " " << r + 1 << endl;
cout << c1 + 1 << " " << c2 + 1 << endl;
return ;
}
}
}
}
cout << "YES" << endl;
}
int main(){
while(cin >> n >> m)
{
read();
solve();
//清空工作
for(int i = 0; i < n; i++)
Text[i].clear();
IDcache.clear();
Strcache.clear();
}
return 0;
}
感想:
这是在网上copy大神的代码...加了一点笔记...实在是想不出来。
然后看完他的代码之后......唉我还是没有好好读书,lrj大大已经在分析里面讲了思路然而我就是不会用...啊啊啊重新来过吧集合栈计算机!!!!