斜率在解题中的巧用

斜率这个概率很简单,描述了几何线的变化。恰当的运用它能让整个思维变得开阔。

51nod 1451 合法三角形
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1451

有n个不同的点,问有多少组三元组能构成面积非0的三角形。

Input
单组测试数据。
第一行一个整数n (1 ≤ n ≤ 2000),表示点的数目。
接下来n行,每行包含两个整数 xi, yi ( -100 ≤ xi, yi ≤ 100),表示第i个点的坐标。输入保证点是两两不同的。
Output
输出合法的三角形数目。

不用三边长关系来判断能否构成三角形,直接考虑各个点的组合。
最简单的情况下,选三个不同的点可以组成三角形.
一般情况下,存在三点共线的情况,除去它们。(注:斜率相等不一定共线啊,但是共线一定斜率相等)
抓住共线一定斜率相等的特点不断排除不该有的三角形。
拓展:三重循环的执行次数等于 n(n-1)(n-2)/6,推广,一个长度为n的m重循环的执行次数就是: (组合学的角度更好理解)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=2e3+10,M=4e6+10;
const double eps=1e-7;
typedef long long LL;
struct point{
    double x,y;
}p[N];
double k[M];
double getk(point a,point b){
    if(a.x==b.x)  return 400;   // 正无穷
    return (b.y-a.y)/(b.x-a.x);
}
int cmp(double a,double b){
    return a-b<-eps;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    LL n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        LL ans=n*(n-1)*(n-2)/6;
        int cnt=0;
        k[0]=-800;
        for(int i=0;i<n;i++){
            cnt=0;
            for(int j=i+1;j<n;j++){
                k[++cnt]=getk(p[i],p[j]);
            }
            sort(k+1,k+cnt+1,cmp);
            LL rp=1;
            for(int j=1;j<=cnt;j++){
                if(fabs(k[j-1]-k[j])<eps) rp++;
                else {
                    ans=ans-rp*(rp-1)/2;
                    rp=1;
                }
            }
            ans=ans-rp*(rp-1)/2;
        }
        printf("%lld\n",ans);
    }
    return 0;
}


codeforce 514B - Han Solo and Lazer Gun
http://codeforces.com/problemset/problem/514/B
大意:求解
所有点过特定点产生多少条直线
分析:用斜率计算,借助STL set

#include <iostream>
#include <cstdio>
#include <cmath>
#include <set>
using namespace std;
const double PI=acos(-1.0);
const int N=1e3+10;
struct point{
    int x,y;
}p[N];
double k[N];
int main()
{
    double INF=tan(PI/2);
    int n,x0,y0;
    while(~scanf("%d%d%d",&n,&x0,&y0)){
        int top=0;
        for(int i=0;i<n;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
            if(p[i].x==x0) k[top++]=INF;
            else k[top++]=(p[i].y-y0)*1.0/(p[i].x-x0);
        }
        set<double> mp(k,k+top);
        printf("%d\n",mp.size());
    }
    return 0;
}


hdu 4310 Hero
http://acm.hdu.edu.cn/showproblem.php?pid=4310
大意:有n个怪,英雄只能一次攻击一个怪,对其造成1点的伤害。当攻击的时候所有的怪也来攻击英雄,对Hero造成所有DPS的和的伤害(可以理解成怪的攻击力的和)。当怪的HP值(可以理解为防御力)变成0时,它被消灭。问怎样设计可以保证消灭所有的怪,且自己的伤害最小? 输出最小值。

分析:也含有比值(斜率的思想)。不过要处理一下,

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct node{
    int d,h;
}p[25];
int cmp(node t1,node t2){
    return t1.d*t2.h>t1.h*t2.d;
}
int main()
{
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            scanf("%d%d",&p[i].d,&p[i].h);
        }
        sort(p,p+n,cmp);
        int ans=0,sum=0;
        for(int i=0;i<n;i++){
            sum=0;
            for(int j=i;j<n;j++){
                sum+=p[j].d;
            }
            ans+=sum*p[i].h;
        }
        printf("%d\n",ans);
    }
    return 0;
}

lydsy 2659 [Beijing wc2012]算不出的算式
大意:求解式子
其中p和q是两个奇质数
分析:数形结合
k=q/p和k=p/q的两条直线关于y=x对称,
刚好可以看做小矩形的一部分S
所以,一般情况下和的结果就是小矩形的面积。
但是当p=q时,向下取整就是本身,所以还要再加上对角线段的长一次

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
int main()
{
    LL p,q;
    while(~scanf("%lld %lld",&p,&q)){
        LL ans=(p/2)*(q/2);
        if(p==q) ans=ans+p/2; //再加上一次直线上的点
        printf("%lld\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值