《算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge。
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。
文章目录
- 题目描述
- 题解
- C++代码
- Java代码
- Python代码
“ 盲文文字编码” ,链接: http://oj.ecustacm.cn/problem.php?id=2141
题目描述
【题目描述】 盲文文字编码由一些凸起的点组成。
如下图所示,我们使用坐标 (0,2),(1,1)表示左侧盲文文字,用坐标(0,1)(1,0)表示右侧盲文文字。
注意:左右图可以通过平移得到,因此被认为是统一文字编码。
现在给你 n 个文字,请判断存在多少个不同的文字。
【输入格式】 输入第一行为正整数 n,表示存在 n 个文字,1≤n≤100000。
接下来存在 n 部分,每部分第一行为正整数 m ,表示这个文字由 m 个点组成1≤m≤1000。
接下来m行,每行包含两个整数 x 和 y,-1000≤x,y≤1000。
输入保证总点数不超过1000000。
【输出格式】 输出一个整数表示答案。
【输入样例】
样例1:
2
2
0 2
1 1
2
0 1
1 0
样例2:
2
3
-1 0
0 1
1 0
3
-1 0
0 -1
1 0
【输出样例】
样例1:
1
样例2:
2
题解
题意是,如果一个图案中的黑点通过平移能到达另一个图案,那么这两个图案就是一样的。由于只需要平移,不需要旋转,处理比较简单。只需要把所有图案的左下角黑点都平移到原点,即可判断有多少不同的图案。
图案的左下角平移到原点后,这个图案的其他点也平移到相应的位置。具体操作是把图案的所有坐标排序,找到左下角的点P,平移到原点,其他点的坐标减去P的坐标得到新坐标。把每个图案的所有坐标存到vector中;对所有图案用set判重。
【重点】 set的应用。
C++代码
代码的复杂度:共n个文字,第14行对每个文字排序是O(mlogm)的,第18行插入到set是O(logn)的,总复杂度O(n(mlogm+logn))。
#include<bits/stdc++.h>
using namespace std;
set<vector<pair<int,int>>>tot;
int main(){
int n;
scanf("%d", &n);
while(n--){
int m; scanf("%d", &m);
vector<pair<int,int> >a; //用vector存一个图案a
while(m--){ //读一个图案的m个点
int x, y; scanf("%d%d", &x, &y);
a.push_back(make_pair(x, y));
}
sort(a.begin(), a.end()); //把这个图案的m个点排序,先x从小到大,x相同再y从小到大
int delta_x = a[0].first, delta_y = a[0].second;
for(auto & x : a) //把最左下点移到原点,其他点平移到相应位置
x.first -= delta_x, x.second -= delta_y;
tot.insert(a); //插入到set tot中,判重
}
cout<<tot.size()<<endl;
return 0;
}
Java代码
在使用Set<List>类型时,确保在添加元素之前先正确实现equals()和hashCode()方法,以避免重复元素被添加到集合中。
import java.util.*;
import java.io.*;
class Main {
static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException {
Set<List<Point>> tot = new HashSet<>();
int n = Integer.parseInt(input.readLine().trim());
for (int i = 0; i < n; i++) {
int m = Integer.parseInt(input.readLine().trim());
List<Point> a = new ArrayList<>();
for (int j = 0; j < m; j++) {
String[] line = input.readLine().trim().split("\\s+");
int x = Integer.parseInt(line[0]);
int y = Integer.parseInt(line[1]);
a.add(new Point(x, y));
}
Collections.sort(a, new PointComparator());
int delta_x = a.get(0).x;
int delta_y = a.get(0).y;
for (int j = 0; j < m; j++) {
a.get(j).x -= delta_x;
a.get(j).y -= delta_y;
}
tot.add(a);
}
System.out.println(tot.size());
}
static class PointComparator implements Comparator<Point> {
public int compare(Point p1, Point p2) {
if (p1.x != p2.x) return p1.x - p2.x;
else return p1.y - p2.y;
}
}
static class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass())
return false;
Point point = (Point) obj;
return x == point.x && y == point.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
}
Python代码
from functools import cmp_to_key
import sys
input = sys.stdin.readline #加这句后读入会快些
def sort_points(p1, p2):
if p1[0] != p2[0]: return p1[0] - p2[0] #x坐标不等,比较x
else: return p1[1] - p2[1] #x坐标相等,比较y
tot = set()
n = int(input())
for i in range(n):
m = int(input())
a = []
for j in range(m):
x, y = map(int, input().split())
a.append((x, y))
a.sort(key=cmp_to_key(sort_points))
delta_x, delta_y = a[0]
a = [(x - delta_x, y - delta_y) for x, y in a]
tot.add(tuple(a))
print(len(tot))