您的位置:首页 > 其它

POJ 1971 Parallelogram Counting

2016-05-01 01:25 459 查看

题目链接:

http://poj.org/problem?id=1971

题意:

二维空间给n个任意三点不共线的坐标,问这些点能够组成多少个不同的平行四边形。

题解:

使用的平行四边形的判断条件:对角线互相平分的四边形是平行四边形。

所以我们枚举每一条线段,如果有两条线段的中点是重合的,那么这四个顶点就能构成一个平行四边形,也就是说每条线段我们只要维护中点就可以了。

1、map维护中点:(数据比较大,t了)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<utility>
using namespace std;
typedef long long LL;

const int maxn = 1111;

int n;
int x[maxn],y[maxn];
map<pair<int,int>,int> mp;

void init(){
mp.clear();
}

int main(){
int tc;
scanf("%d",&tc);
while(tc--){
init();
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d",x+i,y+i);
}
int ans=0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
ans+=mp[make_pair(x[i]+x[j],y[i]+y[j])];
mp[make_pair(x[i]+x[j],y[i]+y[j])]++;
}
}
printf("%d\n",ans);
}
return 0;
}


2、用hash做(vector来建表)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<utility>
#include<vector>
using namespace std;
typedef long long LL;

const int maxn = 1111;
//可能是因为vector<int> tab[mod]的初始化影响很大
//1e3+7跑2985MS 1e4+7跑1282MS 1e5+7跑1750MS 1e6+7跑4532MS
const int mod = 1e3+7;

struct Point {
int x, y, cnt;
Point(int x, int y, int cnt = 0) :x(x), y(y), cnt(cnt) {}
Point() { cnt = 0; }
}pt[maxn];

int n;
vector<Point> tab[mod];
int Hash(const Point& p) {
//LL tmp = (p.x) *1000000007 + p.y;
int tmp = ((p.x << 2) + (p.x >> 4)) ^ (p.y << 10); //折叠法,比上面一个稍微快一点
//注意哈希出来的要是非负数
tmp = (tmp%mod + mod) % mod;
return tmp;
}

int add(const Point& p) {
int key = Hash(p);
int pos = -1;
for (int i = 0; i<tab[key].size(); i++) {
Point& tmp = tab[key][i];
if (p.x == tmp.x&&p.y == tmp.y) {
pos = i; break;
}
}
int ret = 0;
if (pos == -1) {
tab[key].push_back(Point(p.x, p.y, 1));
}
else {
ret = tab[key][pos].cnt;
tab[key][pos].cnt++;
}
return ret;
}

void init() {
for (int i = 0; i<mod; i++) tab[i].clear();
}

int main() {
int tc;
scanf("%d", &tc);
while (tc--) {
init();
scanf("%d", &n);
for (int i = 0; i<n; i++) {
scanf("%d%d", &pt[i].x, &pt[i].y);
}
int ans = 0;
for (int i = 0; i<n; i++) {
for (int j = i + 1; j<n; j++) {
Point p = Point(pt[i].x + pt[j].x, pt[i].y + pt[j].y);
ans += add(p);
}
}
printf("%d\n", ans);
}
return 0;
}


3、用邻接表做散列表,初始化可以省一些时间 954MS

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<utility>
#include<vector>
using namespace std;
typedef long long LL;

const int maxn = 1111;

const int mod = 1e6+7;

struct Point {
int x, y, cnt, ne;
Point(int x, int y, int cnt = 0) :x(x), y(y), cnt(cnt) {}
Point(int x, int y, int cnt, int ne) :x(x), y(y), cnt(cnt), ne(ne) { }
Point() { cnt = 0; }
}pt[maxn],egs[maxn*maxn];

int n;
int tab[mod],tot;
int Hash(const Point& p) {
LL tmp = (p.x) *1000000007 + p.y;
//    int tmp = ((p.x << 2) + (p.x >> 4)) ^ (p.y << 10); //折叠法,比上面一个稍微快一点
//注意哈希出来的要是非负数
tmp = (tmp%mod + mod) % mod;
return tmp;
}

int add(const Point& p) {
int key = Hash(p);
int pos = -1,_p=tab[key];
while (_p != -1) {
Point& e = egs[_p];
if (p.x == e.x&&p.y == e.y) {
pos = _p; break;
}
_p = e.ne;
}
int ret = 0;
if (pos == -1) {
egs[tot] = Point(p.x, p.y, 1, tab[key]);
tab[key] = tot++;
}
else {
ret = egs[pos].cnt;
egs[pos].cnt++;
}
return ret;
}

void init() {
memset(tab, -1, sizeof(tab));
tot = 0;
}

int main() {
int tc;
scanf("%d", &tc);
while (tc--) {
init();
scanf("%d", &n);
for (int i = 0; i<n; i++) {
scanf("%d%d", &pt[i].x, &pt[i].y);
}
int ans = 0;
for (int i = 0; i<n; i++) {
for (int j = i + 1; j<n; j++) {
Point p = Point(pt[i].x + pt[j].x, pt[i].y + pt[j].y);
ans += add(p);
}
}
printf("%d\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: