UVA

/*

   A.该题思路:
   如果四重循环枚举 r1, r2, c1, c2,那么枚举时间过大,肯定会TLE
   
   解决方法:
   只枚举 c1, c2, 然后从上到下扫描各行。每次碰到一个新的行r,把c1 和 c2两列的内容作为一个二维数组存入map,如果map的键值已经存在这个二元组,二元映射到的就是所要求的r1,而当前行就是r2
   
   细节优化:
   如何表示由c1 和 c2 构成的二元组?
   a.直接用两个字符串拼接成一个长字符串(中间用一个不可能出现的字符分隔),但是速度比较慢(因为map再查找元素时,要进行字符串的比较操作)
   
   b.(更值得推荐)
   在主循环之前先做一个预处理--给所有字符串分配一个编号,则整个数据库中每个单元格都变成了整数,上述二元组就变成了两个整数
   

  B. 一些说明
  1.
  这题和 UVA - 12096 The SetStack Computer 又异曲同工之妙,链接见下:
  http://blog.csdn.net/mofushaohua_ln/article/details/77714856
  
  两题的相似之处在于,都采用了为元素编写一个ID,用 ID去对应真正的元素的思想
  
  而两者也有不同的地方,主要在于:
   UVA - 12096 之所以将 Set 标号,是因为题目是要构造集合的集合并压栈,很难真正去用程序来表示出集合的集合,所以分配ID,把集合等效为其ID,在必要时在通过ID去找到对应的集合,势在必行
   
   而这道题,其实是可以拼接字符串存入map,但关键是string类太慢,string的比较所需的时间可能让人无法接受
   
   所以,一个是因为“不得不为”, 一个是因为“这样更好”,其实是有区别的
   
   2.注意相等的两行两列,列并不一定要相邻,在枚举c1,c2的时候,务必两重循环
   
   3.注意判断两列是否有相等元素时,是通过 map<node,int>findrow 是否存在判断的,所以每次重新枚举两列的组合,都要重新清空findrow
   
   4. 注意在输入新一轮数据之前,有关的 map 和 vector都要先清空,其中IDmap需要逐行清空
   
   5. 
   
   如果要用map对自定义类型进行查找,一定不要忘记了重载 < ,相关解释可见:
   http://bbs.csdn.net/topics/190076742
   
   注意重载小于号时,要设置为class类的常函数
   至于为什么要这样,目前
   我也没有太明白,但是如果函数外不加const, 会编译错
   
   有关常函数的知识复习可参见这个blog:
   http://blog.csdn.net/whyglinux/article/details/602329
   
   6.对于输入的问题,其实该博主的这个方法确实略有些麻烦
   刘汝佳前辈的代码(他的代码可见本博文法二)中,是用读取整行stinrg,再用stringstream来找逗号的思路,但是《入门经典》P105曾有言:
   虽然string和stringstream很方便,但string很慢,sstream更慢,应谨慎使用
   
   所以,其实博主应该是出于对于时限的考虑,虽然这题没卡那么严,但是知道卡得严时,应该怎么处理,也是十分必要的
   
   
   声明:
   代码参考了:
   http://blog.csdn.net/wowowoc/article/details/40554525
   
*/



#include <iostream>
#include <cstdio>
#include <map>
#include <vector>
#include <string>
using namespace std; 
const int ROW = 1e4 + 10;
const int COL = 15; 
int n, m;

map<string, int> IDcache;
vector<string> Scache; //set cache
vector<int> IDmap[ROW]; //IDmap[i][j]表示位置(i+1, j+1)对应的字符串的ID

struct node
{
	int x, y;
	node(int _x, int _y):x(_x), y(_y){ }
	bool operator < (const node& a) const
	{
		return (x < a.x) || (x == a.x && y < a.y); //如果要将自定义的结构体作为map的键值,则必须重载 < 号, 
	}
};
map<node, int> findrow; //node对应的是该行在r1, r2列的两个字符串的ID组成的集合,如果这两个字符串已经出现过了,说明找到了,若没有,则将该行对应下标存作 findrow,作为 node(key)对应的的值(value)

//找到字符串s的对应ID,如果找不到,就分配一个ID 
int ID (string s)
{
	if (IDcache.count(s)) return IDcache[s];
	Scache.push_back(s);
	return IDcache[s] = Scache.size() - 1;
}

void input()
{
	string s;
	char ch = getchar();
	for (int i = 0; i < n; i++)
	{
		while (1)
		{
			ch = getchar(); //接受输入完n、m之后得到的回车
			if (ch == '
' || ch == '
') // 说明该行(m个字符串的)读取结束,为当前串分配ID,ID压入IDmap[i]
			{
				IDmap[i].push_back(ID(s));
				s.clear();
				break;
			}
			else if (ch != ',') //说明只是读入正常的字符,将它们放入当前串中
			{
				s += ch;
			}
			else //,说明该行又读完了一串(一列),分配ID,并将ID压入IDmap[i]
			{
				IDmap[i].push_back(ID(s));
				s.clear();
			}
		}
	}
} 

void solve()
{
	int x, y, c1, c2, r;
	for (c1 = 0; c1 < m; c1++)
	for (c2 = c1 + 1; c2 < m; c2++)
	{
		findrow.clear();
		for (r = 0; r < n; r++)
		{
			x = IDmap[r][c1]; y = IDmap[r][c2];
			node t(x, y);
			if (!findrow.count(t)) findrow[t] = r;
			else
			{
				cout << "NO" << endl;
				cout << findrow[t] + 1 << " " << r + 1 << endl;
				cout << c1 + 1 << " " << c2 + 1 << endl;
				return;
			}
			
		}
	}
	cout << "YES" << endl;
}

void ReInit()
{
	for (int i = 0; i < n; i++) IDmap[i].clear();
	IDcache.clear(); Scache.clear();
}

int main()
{
	while (cin >> n >> m)
	{
		input();
		solve();
		ReInit();
	}
	return 0;
}


原文地址:https://www.cnblogs.com/mofushaohua/p/7789441.html