UVA 11123 - Counting Trapizoid(计数问题+容斥)

UVA 11123 - Counting Trapizoid

题目链接

题意:给定一些点,不重复,求出一共有几个梯形

思路:先把所有两点组成直线求出来,然后排序,斜率相同的C2n个,然后再扣除掉重叠的直线情况和长度相等情况(这样为平行四边形或矩形),由于扣除的时候会重复扣掉重叠和相等,所以在加回来,这是容斥原理。

代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;

const double eps = 1e-9;
const double pi = acos(-1.0);
const int N = 205;
int n, ln;
struct Point {
    double x, y;
} p[N];

struct Line {
    double l, a, b, c, k, y;
} l[N * N];

bool cmpk(Line a, Line b) {
    return a.k < b.k;
}

bool cmpl(Line a, Line b) {
    return a.l < b.l;
}

bool cmpy(Line a, Line b) {
    if (fabs(a.y - b.y) < eps)
	return a.l < b.l;
    return a.y < b.y;
}

Line build(Point a, Point b) {
    Line ans;
    ans.l = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    ans.a = b.y - a.y, ans.b = a.x - b.x, ans.c = ans.a * a.x + ans.b * a.y;
    ans.k = atan2(ans.a, -ans.b);
    if (ans.k < 0 || fabs(ans.k) < eps) ans.k += pi;
    if (fabs(ans.b) < eps) ans.y = ans.c / ans.a;
    else ans.y = ans.c / ans.b;
    return ans;
}

long long C(long long n) {
    return n * (n - 1) / 2;
}

long long solve() {
    sort(l, l + ln, cmpk);
    long long ans = 0, cnt = 0;
    Line save[N * N];
    int sn = 0;
    l[ln++].k = -1;
    cnt = 0;
    for (int i = 0; i < ln; i++) {
	if (!i || fabs(l[i].k - l[i - 1].k) < eps) {
	    save[sn++] = l[i];
	    cnt++;
	    continue;
	}
	ans += C(cnt);
	cnt = 0;
	sort(save, save + sn, cmpl);
	for (int j = 0; j < sn; j++) {
	    if (!j || fabs(save[j - 1].l - save[j].l) < eps) {
		cnt++;
		continue;
	    }
	    ans -= C(cnt);
	    cnt = 1;
	}
	ans -= C(cnt);
	cnt = 0;
	sort(save, save + sn, cmpy);
	for (int j = 0; j < sn; j++) {
	    if (!j || fabs(save[j - 1].y - save[j].y) < eps) {
		cnt++;
		continue;
	    }
	    ans -= C(cnt);
	    cnt = 1;
	}
	ans -= C(cnt);
	cnt = 0;
	for (int j = 0; j < sn; j++) {
	    if (!j || (fabs(save[j - 1].y - save[j].y) < eps && fabs(save[j - 1].l - save[j].l) < eps)) {
		cnt++;
		continue;
	    }
	    ans += C(cnt);
	    cnt = 1;
	}
	ans += C(cnt);
	sn = 0;
	save[sn++] = l[i];
	cnt = 1;
    }
    return ans;
}

int main() {
    int cas = 0;
    while (~scanf("%d", &n) && n) {
	ln = 0;
	for (int i = 0; i < n; i++)
	    scanf("%lf%lf", &p[i].x, &p[i].y);
	for (int i = 0; i < n; i++) {
	    for (int j = i + 1; j < n; j++) {
		l[ln++] = build(p[i], p[j]);
	    }
	}
	printf("Case %d: %lld\n", ++cas, solve());
    }
    return 0;
}

UVA 11123 - Counting Trapizoid(计数问题+容斥)

时间: 2024-08-05 15:20:24

UVA 11123 - Counting Trapizoid(计数问题+容斥)的相关文章

uva 11123 - Counting Trapizoid(容斥+几何)

题目链接:uva 11123 - Counting Trapizoid 题目大意:给定若干个点,问有多少种梯形,不包括矩形,梯形的面积必须为正数.因为是点的集合,所以不会优重复的点. 解题思路:枚举两两点,求出该条直线,包括斜率k,偏移值c,以及长度l.已知梯形的性质,一对对边平行,也就是说一对平行但是不相等的边. 所以将所有线段按照斜率排序,假设对于某一斜率,有m条边,那么这m条边可以组成的含平行对边的四边形有C(2m),要求梯形还要减掉长度相同以及共线的情况,分别对应的是l相同和c相同,但是

Uva 12075 Counting Triangles(容斥)

/* 思路:1.先选三个点 2.去掉同行情况 3.去掉同列情况 4.枚举矩形大小去掉重复情况 */ #pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue&g

UVA 1436 - Counting heaps(计数问题)

UVA 1436 - Counting heaps 题目链接 题意:给定一个树的结构,放1-n数字进去,父亲结点值必须小于子节点,问情况有几种. 思路:f[u]表示以u为子树的情况,那么子树情况为f(v1), f(v2), f(v3)... f(vn).去组成子树相当于从中选s(v1), s(v2), s(v3) ... s(vn).根据组合数学,情况为f(v1) f(v2) ... f(vn) (s(u) - 1)! \ (s(v1)! s(v2)! ... * s(vn)!)化简后得到公式:

bzoj 1914: [Usaco2010 OPen]Triangle Counting 数三角形 容斥

1914: [Usaco2010 OPen]Triangle Counting 数三角形 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 272  Solved: 143[Submit][Status] Description 在 一只大灰狼偷偷潜入Farmer Don的牛群被群牛发现后,贝西现在不得不履行着她站岗的职责.从她的守卫塔向下瞭望简直就是一件烦透了的事情.她决定做一些开发智力的小练习,防止她睡 着了.想象牧场是一个X,Y平面的网格.她将N

UVA 11186 - Circum Triangle(计算几何+容斥)

这题用n^2的算法能过,先任意枚举两点,和圆心组成的三角形求面积,这个面积可能会被加(n - 2)次,但是要注意,如果有3点是在同一侧,那么要减去,于是在枚举一遍,每次枚举一个点,然后枚举和这个点度数相差180以内的点,求面积,这个面积要减去2 * (j - i + 1)次 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespac

uva 10542 - Hyper-drive(容斥)

题目链接:uva 10542 - Hyper-drive 题目大意:给定n维空间的线段,问说线段经过几个格子. 解题思路:对于线段可以将一点移动至原点,变成 (0,0)到(a,b)这条线段,以二维为例,每次会从一个格子移动到另一个格子,可以是x+1坐标,也可以是y+1,所以总的应该是a+b-1,扣除掉x+1,y+1的情况gcd(a,b)-1 (原点).映射成n维就要用容斥原理计算结果. /*********************** * (0, 0, 0, ...) -> (a, b, c,

uva 10458 - Cricket Ranking(容斥+高精度)

题目连接:uva 10458 - Cricket Ranking 题目大意:给定k和n,表示有k个比赛,总共要的n分,每个比赛可以得l~r的分数,问说可以有多少种得分方式. 解题思路:容斥,可以参考Codeforces 451E. #include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const int MAXN = 1005

UVA 11806 组合数学+容斥

UVA: https://vjudge.net/problem/UVA-11806 题意:给你一个n×mn×m的矩阵网格和kk个人,问有多少种方法使得每一个格子只放一个人,并且第一行,最后一行,第一列,最后一列都有人.直接枚举似乎有难度,我们考虑容斥.rr行cc列放kk个人的方案数是(r×ck)(r×ck),那么由容斥原理,总方案为 ans=U?A?B?C?D+AB+AC+AD+-+ABCDans=U?A?B?C?D+AB+AC+AD+-+ABCD 其中UU表示没有限制的方案数,A,B,C,DA

uva 11806 Cheerleaders(容斥)

题意:如何摆放拉拉队的问题,在矩形网格m*n中,k名拉拉队员,要求四周网格中each side有至少一名拉拉队员,corner有人算两边,问有多少种摆法? 思路:容斥: c[m*n][k] -- c[(n-1)*m][k] U c[(n-1)*m][k] U c[n*(m-1)][k] U c[n*(m-1)][k] #include<cstdio> #include<iostream> #include<cstring> #define mod 1000007 usi