zoukankan      html  css  js  c++  java
  • HDU_6590 Code 【凸包】

    一、题目

      Code

    二、分析

      题目描述了一大堆东西,就是想问二维空间里,能不能确定$d  w_1   w_2$使得函数满足$f(x_1,x_2) = y$,并且$sign(x)$函数是一个信号函数,只取3种值。

      那么将函数拆开其实就是$d + w_{1}x_{i_1} + w_{2}x_{i_2} = y$,因为$y$给定,发现就是一个二维平面里的直线,我们只需要将所有$y=1$和$y=-1$的点分类,能不能确定$w_1$和$w_2$使得所有点的值都等于$-1$或者$1$,即$<0$或者$>0$而等于$0$的情况相当于就是一条直线,将两类点分开。所以转换一下就是求两个凸包是否相交。

    三、AC代码

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 #define ll long long
      5 #define Min(a,b) ((a)>(b)?(b):(a))
      6 #define Max(a,b) ((a)>(b)?(a):(b))
      7 #define P pair<int, int>
      8 const double EPS = 1e-8;
      9 const int MAXN = 1e2+13;
     10 const int INF = 1e5;
     11 
     12 //带误差比较,返回x是否等于y
     13 inline bool dcmp(double x, double y = 0)
     14 {
     15     return fabs(x - y) <= EPS;
     16 }
     17 
     18 //向量
     19 //需要使用一个原点到(x,y)的有向线段表示
     20 typedef struct Vec
     21 {
     22     double x, y;
     23 
     24     Vec(double x = 0, double y = 0) : x(x),y(y) {}
     25 
     26     //向量相加
     27     Vec operator+(const Vec &v) const{
     28         return Vec(x + v.x, y + v.y);
     29     }
     30 
     31     //向量相减
     32     Vec operator-(const Vec &v) const{
     33         return Vec(x - v.x, y - v.y);
     34     }
     35 
     36     //向量数乘 即向量*数d
     37     Vec operator*(double d) const{
     38         return Vec(x * d, y * d);
     39     }
     40 
     41     Vec operator/(double d) const{
     42         return Vec(x / d, y / d);
     43     }
     44     
     45     //范数,及长度的平方
     46     double norm() const{
     47         return x * x + y * y;
     48     }
     49 }Pt;
     50 
     51 //点乘
     52 double dot(const Vec &a, const Vec &b)
     53 {
     54     return a.x * b.x + a.y * b.y;
     55 }
     56 
     57 //叉乘
     58 //叉乘可以表示四边形的面积
     59 double cross(const Vec &a, const Vec &b)
     60 {
     61     return a.x * b.y - a.y * b.x;
     62 }
     63 
     64 //线段,两个点表示
     65 struct Seg
     66 {
     67     Pt a, b;
     68 
     69     Seg(const Pt &a, const Pt &b) : a(a), b(b) {}
     70 
     71     //线段包含点(点在线段上)
     72     //先判断是否叉乘等于 0, 如果等于0表示点在线段所在的直线上
     73     //再判断点乘是否小于等于0
     74     //小于0表示两向量夹角为180,刚好在线段内,
     75     //等于0表示刚好在线段两端
     76     bool include(const Pt &p) {
     77         return dcmp(cross(a - p, b - p)) && dot(a - p, b - p) <= 0;
     78     }
     79 };
     80 
     81 //直线,两个点表示
     82 struct Line
     83 {
     84     Pt a, b;
     85 
     86     Line() {}   //提供一个不需要参数的构造函数
     87     Line(const Pt &a, Pt &b) : a(a), b(b) {}
     88 
     89     //点在直线上
     90     bool include(const Pt &p) const {
     91         return dcmp(cross(a - p, b - p));
     92     }
     93 
     94     //两直线关系
     95     //  1 表示两直线相交(1交点)
     96     //  0 表示两直线平行(0交点)
     97     // -1 表示两直线重合(无数交点)
     98     static int relation(const Line &a, const Line &b) {
     99         if(a.include(b.a) && a.include(b.b))    return -1;
    100         else if(dcmp(cross(a.b - a.a, b.b - b.a)))  return 0;
    101         else return 1;
    102     }
    103 
    104     //求两直线交点(若有一个交点)
    105     static Pt intersect(const Line &a, const Line &b) {
    106         double s1 = cross(b.a - a.a, b.b - a.a), s2 = cross(b.b - a.b, b.a - a.b);
    107         return a.a + (a.b - a.a) * s1 / (s1 + s2);
    108     }
    109 
    110 };
    111 
    112 //凸包的交点
    113 int n;
    114 Pt a[MAXN + 1];
    115 
    116 //凸包极角比较函数
    117 inline bool compare(const Pt &a, const Pt &b)
    118 {
    119     //以第一个点为原点的两个向量
    120     Vec va = a - ::a[1], vb = b - ::a[1];
    121     double t = cross(va, vb);
    122     //t>0 表示b的极角大,b在a的逆时针方向
    123     //t<0 表示a的极角大,b在a的顺时针方向
    124     //t=0 表示a与b极角相同,则比较长度
    125     if(!dcmp(t)) return t > 0;
    126     else return va.norm() < vb.norm();
    127 }
    128 
    129 //多边形
    130 struct Poly
    131 {
    132     std::vector<Pt> pts;
    133     
    134     //判断点是否在多边形内
    135     //射线法,作平行于x轴的线
    136     bool include(const Pt &p) const {
    137         int cnt = 0;
    138         //判断与每条边是否有交点
    139         for(size_t i = 0; i < pts.size(); i++) {
    140             //枚举相邻两点
    141             const Pt &a = pts[i], &b = pts[(i+1)%pts.size()];
    142 
    143             //如果点p在边AB上
    144             if(Seg(a, b).include(p))    return true;
    145 
    146             double d1 = a.y - p.y, d2 = b.y - p.y, tmp = cross(a - p, b- p);
    147             //如果tmp >= 0 && d1 >= 0 && d2 <= 0 那么点在多边形内会被标记两次
    148             //将无法排除点在外面刚好记录两次的情况
    149             if( (tmp >= 0 && d1 >= 0 && d2 < 0) || (tmp <= 0 && d1 < 0 && d2 >=0)) cnt++;
    150         }
    151         //因为点可能刚好在外面与边交于一顶点,那么会判断两次
    152         //所以根据判断的次数是否为奇数判断
    153         return cnt % 2 == 1;
    154     }
    155 
    156     //多边形面积
    157 
    158     bool area() const {
    159         double res = 0;
    160         for(size_t i = 0; i < pts.size(); i++) {
    161             //枚举两个点
    162             const Pt &a = pts[i], &b = pts[(i+1) % pts.size()];
    163             res += cross(a, b);
    164         }
    165         return res/2;
    166     }
    167     
    168     //求凸包,结果存储在自身pts中
    169     void convex() {
    170         int id = 1;
    171         //找最左下角的点当原点
    172         for(int i = 1; i <= n; i++) {
    173             if(a[i].x < a[id].x || (a[i].x == a[id].x && a[i].y < a[id].y))
    174                 id = i;
    175         }
    176         if(id != 1) std::swap(a[1], a[id]);
    177 
    178         //极角排序
    179         std::sort(a + 2, a + n + 1, &compare);
    180 
    181         //扫描
    182         pts.push_back(a[1]);
    183         for(int i = 2; i <= n; i++) {
    184             //比较,如果最后一个点在凸包内,则被弹出
    185             while(pts.size() >= 2 && cross(a[i] - pts[pts.size() - 2], pts.back() - pts[pts.size() - 2]) >= 0 )
    186                 pts.pop_back();
    187             pts.push_back(a[i]);
    188         }
    189     }
    190 };
    191 
    192 bool solve(Poly &a, Poly &b)
    193 {
    194     for(int i = 0; i < b.pts.size(); i++) {
    195         if(a.include(b.pts[i]))
    196             return false;
    197     }
    198     for(int i = 0; i < a.pts.size(); i++) {
    199         if(b.include(a.pts[i]))
    200             return false;
    201     }
    202     return true;
    203 }
    204 
    205 Pt c1[MAXN], c2[MAXN];
    206 
    207 int main()
    208 {
    209     freopen("input.txt", "r", stdin);
    210     // freopen("out.txt", "w", stdout);
    211     int T;
    212     scanf("%d", &T);
    213     while(T--) {
    214         int N, x, y, f;
    215         scanf("%d", &N);
    216         Poly p1, p2;
    217         int N1 = 1, N2 = 1;
    218         for(int i = 0; i < N; i++) {
    219             scanf("%d%d%d", &x, &y, &f);
    220             if(f == -1) {
    221                 c1[N1++] = Pt(x+INF, y+INF);
    222             }
    223             else {
    224                 c2[N2++] = Pt(x+INF, y+INF);
    225             }
    226         }
    227         for(int i = 1; i < N1; i++) {
    228             a[i] = c1[i];
    229         }
    230         n = N1 - 1;
    231         p1.convex();
    232         for(int i = 1; i < N2; i++) {
    233             a[i] = c2[i];
    234         }
    235         n = N2 - 1;
    236         p2.convex();
    237         // cout << " py1    " << endl;
    238         // for(int i = 0; i< p1.pts.size(); i++) {
    239         //     cout << p1.pts[i].x << " , " << p1.pts[i].y << endl;
    240         // }
    241         // cout << " py2    " << endl;
    242         // for(int i = 0; i< p2.pts.size(); i++) {
    243         //     cout << p2.pts[i].x << " , " << p2.pts[i].y << endl;
    244         // }
    245         if(solve(p1, p2)) {
    246             puts("Successful!");
    247         }
    248         else puts("Infinite loop!");
    249     }
    250     return 0;
    251 }
  • 相关阅读:
    HDU 4870 Rating(高斯消元 )
    iOS开发者账号详细介绍
    iOS之Block
    CocoaPods 安装和使用
    搭建自己的局域网服务器
    MarkDown语法收集
    正则表达式参考表
    iOS企业级应用打包与部署
    iOS开发之代码加载方式进入APP的界面
    shell脚本小Demo
  • 原文地址:https://www.cnblogs.com/dybala21/p/11413682.html
Copyright © 2011-2022 走看看