kuangbin专题十三基础计算几何总结

本文针对几道计算几何题目提供详细的解题思路与代码实现,包括线段与直线相交判断、最短路径计算、光线传播路径寻找等,强调了枚举端点、细节处理的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

感觉做完没什么进步,不会做的题就去搜题解,没过的题就去找数据。。。下次不能这样!
计算几何我觉得一靠板子,二靠细节。我会在另一篇博客整理出比较好的板子。细节得要自己培养培养,总不能总看网上的数据来过题呀。
C - Segments
题目大意:给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!。
解题思路:如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条线和所有线段相交.
直线肯定经过两个端点。
枚举端点,判断直线和线段是否相交。
细节要注意,判断重合点。
还有就是加入只有一条线段的话,刚好直线是过同一条直线的。
所以保险的做法是枚举所有的两个端点,包括同一条直线的。(kuangbin的题解)
枚举端点是个常见的思路,往往端点就是极端情况。。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<set>
using namespace std;
const double eps = 1e-8;
struct point
{
    int index;
    double ang;
    double x, y;
    point() { x = 0;y = 0; }
    point(double sx, double sy) { x = sx, y = sy; }
    bool operator<(const point &b)const
    {
        if (x != b.x)return x < b.x;
        return y < b.y;
    }

};
struct line
{
    double ang;
    point a, b;line(){}
    line(const point &p1, const point &p2)
    {
        a = p1;
        b = p2;
    }
};


double xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

int opposite_side(point p1, point p2,line l)
{
    double tmp = xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b);
    return  tmp < -eps || tmp < eps;
}
set<point>S;
line lines[105];
int n;
bool check(line a)
{
    for (int i = 1;i <= n;i++)
    {
        point tmp1 = lines[i].a;
        point tmp2 = lines[i].b;
        if (!opposite_side(tmp1, tmp2, a))
            return 0;
    }
    return 1;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        S.clear();

        scanf("%d", &n);
        double x1, y1, x2, y2;
        for (int i = 1;i <= n;i++)
        {
            scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
            S.insert(point(x1, y1));
            S.insert(point(x2, y2));
            lines[i] = line(point(x1, y1), point(x2, y2));
        }
        set<point>::iterator itor,itor2;
        bool flag = false;
        for(itor=S.begin();itor!=S.end();itor++)
            for (itor2 = itor;itor2 != S.end();itor2++)
            {
                if (itor2 == itor)continue;
                line tmp = line(*itor, *itor2);
                if (check(tmp))
                {
                    flag = true;
                    puts("Yes!");
                    itor = S.end();
                    itor--;
                    break;
                }
            }
        if (!flag)
            puts("No!");
    }


}

E - The Doors
这题应该能做出来的,当时蠢了一下。。先计算出端点到其他能到的点的距离,然后跑最短路就行了。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<queue>
using namespace std;

#define eps 1e-8
#define _sign(x) ((x)>eps?1:((x)<-eps?2:0))
#define zero(x) (fabs(x)<eps)

struct point
{
    int index;
    double x, y;
    point() { x = 0, y = 0; }
    point(double sx, double sy)
    {
        x = sx;
        y = sy;
    }
};

struct line
{
    point a, b;
    line() {}
    line(const point &p1, const point &p2)
    {
        a = p1;
        b = p2;
    }
};
vector<line>V;

double xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

int opposite_side(point p1, point p2, line l)
{
    return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) < -eps;
}

int intersect_ex(line u, line v)
{
    return opposite_side(u.a, u.b, v) && opposite_side(v.a, v.b, u);
}

int parallel(line u, line v)
{
    return zero((u.a.x - u.b.x)*(v.a.y - v.b.y) - (v.a.x - v.b.x)*(u.a.y - u.b.y));
}

double dist(line a)
{
    double x = a.a.x - a.b.x;
    double y = a.a.y - a.b.y;
    return sqrt(x*x + y*y);
}

point P[100];
int pcnt;
double map[100][100];
void buildmap()
{
    for(int i=1;i<=pcnt;i++)
        for (int j = i + 1;j <= pcnt;j++)
        {
            map[i][j] = map[j][i] = 50.0;
            line tmp = line(P[i], P[j]);
            bool flag = true;
            for (int k = 0;k < V.size();k++)
            {
                line tmp2 = V[k];
                if (parallel(tmp, tmp2))continue;
                if (intersect_ex(tmp, tmp2))
                {
                    flag = false;
                    break;
                }
            }
            if (flag)
                map[i][j] = map[j][i] = dist(tmp);
        }
}
bool vis[100];
double d[100];

struct HeapNode
{
    int u;
    double d;
    HeapNode(int _u,double _d):u(_u),d(_d){}
    HeapNode(){}
    bool operator<(const HeapNode &b)const
    {
        return d > b.d;
    }
};

double dijkstra()
{
    memset(vis, 0, sizeof(vis));
    for (int i = 1;i <= pcnt;i++)d[i] = 50;
    d[1] = 0;
    priority_queue<HeapNode>Q;
    Q.push(HeapNode(1,d[1]));
    while (!Q.empty())
    {
        HeapNode x = Q.top();Q.pop();
        if (vis[x.u])continue;
        vis[x.u] = 1;
        for (int i = 1;i <= pcnt;i++)if(map[x.u][i]!=50)
        {
            if (d[i] > d[x.u] + map[x.u][i])
            {
                d[i] = d[x.u] + map[x.u][i];
                Q.push(HeapNode(i, d[i]));
            }
        }
    }
    return d[2];
}

int main()
{
    int n;
    while (~scanf("%d", &n) && n != -1)
    {
        pcnt = 0;
        V.clear();
        double tmp1, tmp2, tmp3;
        //line tmp;
        P[++pcnt] = point(0, 5);
        P[++pcnt] = point(10, 5);
        for (int i = 1;i <= n;i++)
        {
            scanf("%lf %lf", &tmp1, &tmp2);
            //P[++pcnt] = point(tmp1, 0);
            P[++pcnt] = point(tmp1, tmp2);
            V.push_back(line(point(tmp1, 0), point(tmp1, tmp2)));
            scanf("%lf %lf", &tmp2, &tmp3);
            P[++pcnt] = point(tmp1, tmp2);
            P[++pcnt] = point(tmp1, tmp3);
            V.push_back(line(point(tmp1, tmp2), point(tmp1, tmp3)));
            scanf("%lf", &tmp2);
            P[++pcnt] = point(tmp1, tmp2);
            V.push_back(line(point(tmp1, tmp2), point(tmp1, 10)));
        }
        buildmap();
        printf("%.2f\n", dijkstra());
    }


}

G - Treasure Hunt
这题一开始我的思路想着把它转换成最短路,不同的房间如果隔着一个墙就连条边,然后和最外面的再连一条边,这样就可以求最短路了。但想了很久不知道怎么划分房间。。
正解还是枚举端点,端点和终点相连的线段看与多少个墙相交(不包括端点)。

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cstring>
using namespace std;
#define eps 1e-5
struct point
{
    double x, y;
    point() { x = 0, y = 0; }
    point(double sx, double sy)
    {
        x = sx;
        y = sy;
    }
}P[100];
int now;
struct line
{
    point a, b;
    line(){}
    line(point p1, point p2)
    {
        a = p1;
        b = p2;
    }
}lines[35];
double aimx, aimy;
int n;

double xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

int opposite_side(point p1, point p2, line l)
{
    return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) < -eps;
}

int intersect_ex(line u, line v)
{
    return opposite_side(u.a, u.b, v) && opposite_side(v.a, v.b, u);
}

void solve()
{
    if (n == 0) { printf("Number of doors = 1\n");return; }
    int ans = 35;
    point aim = point(aimx, aimy);
    for (int i = 1;i <= now;i++)
    {
        line tmp = line(P[i], aim);
        int ctch = 0;
        for (int j = 1;j <= n;j++)
        {
            if (intersect_ex(tmp, lines[j]))
                ctch++;
        }
        ans = min(ans, ctch);
    }
    printf("Number of doors = %d\n", ans+1);
}

int main()
{

    scanf("%d", &n);
    int x1, y1, x2, y2;
    now = 0;
    for (int i = 1;i <= n;i++)
    {
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        P[++now] = point(x1, y1);
        P[++now] = point(x2, y2);
        lines[i] = line(P[now - 1], P[now]);
    }
    scanf("%lf %lf", &aimx, &aimy);
    solve();
}

H - Intersection
本专题傻题之一。题目挺简单的,但这题有几个坑点。
1,给出的矩形的两个点并不一定是按照顺序给出的,需要自己判断。
2,线段在矩形内部也算相交(无语)。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
using namespace std;
#define eps 1e-5
#define zero(x) (fabs(x)<eps)
struct point
{
    int x, y;
    point() { x = 0, y = 0; }
    point(int sx, int sy) { x = sx;y = sy; }
};
int xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

struct line
{
    point a, b;
    line() {}
    line(point _a, point _b) :a(_a), b(_b) {}
};

int dots_inline(point p1, point p2, point p3)
{
    return zero(xmult(p1, p2, p3));
}

int same_side(point p1, point p2, line l)
{
    return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) > eps;
}

int dot_online_in(point p, line l)
{
    return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x)*(l.b.x - p.x) < eps && (l.a.y - p.y)*(l.b.y - p.y) < eps;
}

int intersect_in(line u, line v)
{
    if (!dots_inline(u.a, u.b, v.a) || !dots_inline(u.a, u.b, v.b))
        return !same_side(u.a, u.b, v) && !same_side(v.a, v.b, u);
    return dot_online_in(u.a, v) || dot_online_in(u.b, v) || dot_online_in(v.a, u) || dot_online_in(v.b, u);
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        int x1, y1, x2, y2;
        int x3, y3, x4, y4;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        line a = line(point(x1, y1), point(x2, y2));
        scanf("%d %d %d %d", &x3, &y3, &x4, &y4);
        if (x3 > x4)swap(x3, x4);
        if (y3 < y4)swap(y3, y4);
        point a1 = point(x3, y3), a2 = point(x4, y3), a3 = point(x3, y4), a4 = point(x4, y4);
        line l1 = line(a1, a2), l2 = line(a1, a3), l3 = line(a3, a4), l4 = line(a2, a4);
        if (!intersect_in(a, l1) && !intersect_in(a, l2) && !intersect_in(a, l3) && !intersect_in(a, l4))
        {
            point tmp = a.a;
            if (tmp.x<x4&&tmp.x>x3&&tmp.y<y3&&tmp.y>y4)
                puts("T");
            else
                puts("F");

        }
        else
            puts("T");
    }
}

I - Space Ant
一开始的思路没错,但是样例都没过,就发现我对极角排序有一点错误的理解。叉积极角排序只能排不超过π范围的点,如果超过了就得先按照象限排,再叉积极角排序。
另外atan2那种排序方式范围是-π到π,换句话说就是从第三象限排(如果我没搞错的话)。

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

#define eps 1e-5
#define zero(x) (fabs(x)<eps)


struct point
{
    int index;
    int x, y;
    point(){}
    point(int _x,int _y,int idx):x(_x),y(_y),index(idx){}
};

int xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

double dist(point a, point b)
{
    double x = a.x - b.x;
    double y = a.y - b.y;
    return sqrt(x*x + y*y);
}

struct line
{
    point a, b;
    double ang;
    line(point sa, point sb)
    {
        a = sa;
        b = sb;
    }
    line(){}
    bool operator<(const line &y)const
    {
        if (zero(ang - y.ang))
        {
            return dist(a, b) < dist(y.a, y.b);
        }
        return ang < y.ang;
    }
    void getang()
    {
        ang = atan2(-b.y + a.y, -b.x + a.x);
    }
};
point P[105];
int N;
int ans[105];
int cnt;
point now;
bool cmp(const point &a, const point &b)
{
    int tmp = xmult(a, b, now);
    if (tmp == 0)
        return dist(a, now) < dist(b, now);
    return tmp > 0;
}
void solve(int themin)
{
    cnt = 0;

    now = point(0, themin,0);
    for (int i = 1;i <= N;i++)
    {
        sort(P + i, P + N + 1,cmp);
        ans[++cnt] = P[i].index;
        now = P[i];
    }
    printf("%d", N);
    for (int i = 1;i <= N;i++)
        printf(" %d", ans[i]);
    puts("");
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {

        scanf("%d", &N);
        int idx, x, y;
        int miny = 105;
        for (int i = 1;i <= N;i++)
        {
            scanf("%d %d %d", &idx, &x, &y);
            P[idx] = point(x, y,idx);
            miny = min(miny, y);
        }
        solve(miny);
    }
}

J - Kadj Squares
首先我们要求出所有正方形放的位置,由于题目给的正方形边长是个整数,那么它想x坐标必然是一个小数,所以这里有一个小技巧,就是把它的边长都默认乘 2 2 ,那么它的x坐标就变成整数了。
如何求一个正方形的位置呢,我们可以枚举它之前放好的正方形,先假设它靠在这个正方形上,求出当前的x,然后找到一个最大的x就是他的位置啦。
求完位置后在看它左边的正方形把它遮住了多少,右边的正方形把它遮住了多少,在判断一下就行了。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
using namespace std;

int B[55], L[55];
vector<int>V;
int main()
{
    int n;
    while (~scanf("%d",&n)&&n)
    {
        V.clear();
        int tmp;
        for (int i = 1;i <= n;i++)
        {
            scanf("%d", &tmp);
            int x = tmp;
            L[i] = tmp;
            for (int j = 1;j < i;j++)
            {
                if (tmp >= L[j])
                    x = max(x, B[j] + L[j] + L[j]);
                else
                    x = max(x, B[j] + tmp * 2);
            }
            B[i] = x;
        }

        int ans = 0;
        for (int i = 1;i <= n;i++)
        {
            int Left=0, Right=B[i]+L[i];
            for (int j = 1;j < i;j++)
            {
                int x = B[j] + L[j];
                if (x >= B[i] - L[i])
                    Left = max(Left, x);
            }
            for (int j = i + 1;j <= n;j++)
            {
                int x = B[j] - L[j];
                if (x <= B[i] + L[i])
                    Right = min(Right, x);
            }
            if (Left < Right)V.push_back(i);
        }
        for (int i = 0;i < V.size();i++)
        {
            printf("%d", V[i]);
            if (i != V.size() - 1)printf(" ");
            else
                puts("");
        }
        //printf("%d\n", ans);
    }
}

K - An Easy Problem?!

一道坑题,但不得不说它是道好题。需要判断的地方很多,希望读者自行判断。。
提一点最重要的地方,就是有可能上面的板子遮住了下面的板子,使得一点雨都就不住。
注意精度问题,用C++交。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<stdio.h>
using namespace std;
#define eps 1e-8
#define zero(x) (fabs(x)<eps)
struct point 
{
    double x, y;
    point(double sx, double sy) { x = sx;y = sy; }
    point(){}
};

struct line
{
    point a, b;
    double ang;
    line(){}
    line(point p1, point p2)
    {
        a = p1;b = p2;
    }
    void getang()
    {
        ang = atan2((b.y - a.y) , (b.x - a.x));
    }
};

double xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

int same_side(point p1, point p2, line l)
{
    return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) > eps;
}

int dots_inline(point p1, point p2, point p3)
{
    return zero(xmult(p1, p2, p3));
}

int dot_online_in(point p, line l)
{
    return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x)*(l.b.x - p.x) < eps && (l.a.y - p.y)*(l.b.y - p.y) < eps;
}

int intersect_in(line u, line v)
{
    if (!dots_inline(u.a, u.b, v.a) || !dots_inline(u.a, u.b, v.b))
        return !same_side(u.a, u.b, v) && !same_side(v.a, v.b, u);
    return dot_online_in(u.a, v) || dot_online_in(u.b, v) || dot_online_in(v.a, u) || dot_online_in(v.b, u);
}

point intersection(line u, line v)
{
    point ret = u.a;
    double t = ((u.a.x - v.a.x)*(v.a.y - v.b.y) - (u.a.y - v.a.y)*(v.a.x - v.b.x)) / ((u.a.x - u.b.x)*(v.a.y - v.b.y) - (u.a.y - u.b.y)*(v.a.x - v.b.x));
    ret.x += (u.b.x - u.a.x)*t;
    ret.y += (u.b.y - u.a.y)*t;
    return ret;
}

double area_triangle(point p1, point p2, point p3)
{
    return fabs(xmult(p1, p2, p3)) / 2;
}

int parallel(line u, line v)
{
    return zero((u.a.x - u.b.x)*(v.a.y - v.b.y) - (v.a.x - v.b.x)*(u.a.y - u.b.y));
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        double x1, y1, x2, y2, x3, y3, x4, y4;
        scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);
        point p1 = point(x1, y1), p2 = point(x2, y2), p3 = point(x3, y3), p4 = point(x4, y4);
        if (p1.y < p2.y)
            swap(p1, p2);
        if (p3.y < p4.y)
            swap(p3, p4);
        if (p1.y > p3.y)
        {
            swap(p1, p3);
            swap(p2, p4);
        }
        line a = line(p1, p2);
        line b = line(p3, p4);
        a.getang();b.getang();
        if (p1.x < p2.x&&p3.x<p4.x)
        {
            if (a.ang > b.ang&&p3.x<=p1.x)
            {
                puts("0.00");
                continue;
            }
        }
        if (p1.x > p2.x&&p3.x > p4.x)
        {
            if (a.ang < b.ang&&p3.x>=p1.x)
            {
                puts("0.00");
                continue;
            }
        }

        if (intersect_in(a, b))
        {

            if (zero(a.ang - b.ang))puts("0.00");
            else
            {
                point insec1 = intersection(a, b);
                line c = line(p1, point(p1.x+5, p1.y));
                if (parallel(c, b))
                    puts("0.00");
                else
                {
                    point insec2 = intersection(c, b);
                    printf("%.2f\n", area_triangle(insec1, insec2, p1));
                }
            }

        }
        else
            puts("0.00");
    }


}

L - Pipe
此题初看可能十分困难,但是上下顶点对于限制光线非常关键。首先,我们想到如果一根光线自始至终未曾擦到任何顶点,肯定不是最优的(可以通过平移使之优化)。然后,如果只碰到一个顶点,那也不是最优的,可以通过旋转使他碰到另一个顶点,并且更优,最后要说明,最优光线必然是擦到一个上顶点和一个下顶点。以上三步的证明用反证法并不困难。所以留给读者。
于是有了一个简单的算法,任取一个上顶点和下顶点,形成直线l。若l能射穿左入口,即当x=x0时,直线l在(x0,y0)和(x0,y0-1)之间,则是一条可行光线。再从左到右依次判断每条上,下管壁是否与l相交,相交则求交点,并把交点x与当前最佳值比较,若所有管壁都不与l相交,说明l射穿了整个管道。(算法艺术与信息学竞赛)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<stdio.h>
using namespace std;
#define eps 1e-5
#define zero(x) (fabs(x)<eps)
#define inf 1e10

int sgn(double x)
{
    if (fabs(x) < eps)return 0;
    if (x < 0)return -1;
    return 1;
}

struct point
{
    double x, y;
    point(double sx, double sy)
    {
        x = sx;
        y = sy;
    }
    point(){}
}up[50],dwn[50];
struct line
{
    point a, b;
    line(point sa, point sb)
    {
        a = sa;
        b = sb;
    }
    line(){}
}L[50];

double xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

int opposite_side(point p1, point p2, line l)
{
    return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) < -eps;
}

int intersect_ex(line u, line v)
{
    return opposite_side(u.a, u.b, v) && opposite_side(v.a, v.b, u);
}

int same_side(point p1, point p2, line l)
{
    double tmp= xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b);
    cout << tmp << endl;
    cout << (tmp > eps) << endl;
    return tmp > eps;
}

int dots_inline(point p1, point p2, point p3)
{
    return zero(xmult(p1, p2, p3));
}

int dot_online_in(point p, line l)
{
    return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x)*(l.b.x - p.x) < eps && (l.a.y - p.y)*(l.b.y - p.y) < eps;
}

int intersect_in(line u, line v)
{
    if (!dots_inline(u.a, u.b, v.a) || !dots_inline(u.a, u.b, v.b))
        return !same_side(u.a, u.b, v) && !same_side(v.a, v.b, u);
    return dot_online_in(u.a, v) || dot_online_in(u.b, v) || dot_online_in(v.a, u) || dot_online_in(v.b, u);
}

int n;

double dist(point a, point b)
{
    double x = a.x - b.x;
    double y = a.y - b.y;
    return sqrt(x*x + y*y);
}

point intersection(line u, line v)
{
    point ret = u.a;
    double t = ((u.a.x - v.a.x)*(v.a.y - v.b.y) - (u.a.y - v.a.y)*(v.a.x - v.b.x)) / ((u.a.x - u.b.x)*(v.a.y - v.b.y) - (u.a.y - u.b.y)*(v.a.x - v.b.x));
    ret.x += (u.b.x - u.a.x)*t;
    ret.y += (u.b.y - u.a.y)*t;
    return ret;
}

int Seg_inter_line(line l1, line l2)//判断直线l1和线段l2是否相交
{
    double tmp1 = xmult(l2.a, l1.a, l1.b);
    double tmp2 = xmult(l2.b, l1.a, l1.b);
    return sgn(tmp1)*sgn(tmp2) <= 0;
}

void solve()
{
    line first = line(up[1], dwn[1]);
    double ans = -inf;
    for(int i=1;i<=n;i++)
        for (int j = 1;j <= n;j++)
        {
            line it = line(up[i], dwn[j]); 
            if (Seg_inter_line(it,first))
            {
                for (int k = 1;k <= n;k++)
                {
                    line now = line(up[k], dwn[k]);
                    if (!Seg_inter_line(it, now))
                    {
                        line tmp1 = line(up[k], up[k - 1]);
                        line tmp2 = line(dwn[k], dwn[k - 1]);
                        if (Seg_inter_line(it, tmp1))
                        {
                            point t = intersection(it, tmp1);
                            ans = max(ans, t.x);
                        }
                        if (Seg_inter_line(it, tmp2))
                        {
                            point t = intersection(it, tmp2);
                            ans = max(ans, t.x);
                        }
                        break;
                    }
                    if (k == n)
                    {
                        ans = up[n].x + 1;
                    }
                }


            }
        }
    if (zero(ans - up[n].x-1))
        puts("Through all the pipe.");
    else
        printf("%.2f\n", ans);

}

int main()
{
    while (~scanf("%d",&n)&&n)
    {
        double x, y;
        for (int i = 1;i <= n;i++)
        {
            scanf("%lf %lf", &x, &y);
            up[i] = point(x, y);
            dwn[i] = point(x, y - 1);
        }
        solve();
    }
}

M - Geometric Shapes
本专题最傻的题。本来不想贴的,但感觉代码写的太好了,所以贴上来。。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<string>
#include<math.h>
using namespace std;
#define eps 1e-5
#define zero(x) (fabs(x)<eps)
const double pi = acos(-1);
struct point
{
    double x, y;
    point(double sa, double sb)
    {
        x = sa;
        y = sb;
    }
    point() {}
    bool operator<(const point &b)const
    {
        if (x != b.x)
            return x < b.x;
        return y < b.y;
    }
};

struct line
{
    char s;
    point a, b;
    line(point sa, point sb, char ss)
    {
        a = sa;
        b = sb;
        s = ss;
    }
    line() {}
};
line L[1000];
int lcnt;

point rotate(point v, point p, double angle)
{
    point ret = p;
    v.x -= p.x, v.y -= p.y;
    p.x = cos(angle);
    p.y = sin(angle);
    ret.x += v.x*p.x - v.y*p.y;
    ret.y += v.x*p.y + v.y*p.x;
    return ret;
}

void reads(char s)
{
    char tmp1[50], tmp2[50];
    scanf("%s %s", tmp1, tmp2);
    int x1, y1, x2, y2;
    sscanf(tmp1, "(%d,%d)", &x1, &y1);
    sscanf(tmp2, "(%d,%d)", &x2, &y2);
    point p1 = point(x1, y1);
    point p2 = point(x2, y2);
    point p3, p4;
    point mid = point((x1 + x2 + 0.0) / 2.0, (y1 + y2 + 0.0) / 2.0);
    p3 = rotate(p1, mid, pi / 2);
    p4 = rotate(p1, mid, -pi / 2);

    L[++lcnt] = line(p1, p3, s);
    L[++lcnt] = line(p1, p4, s);
    L[++lcnt] = line(p2, p3, s);
    L[++lcnt] = line(p2, p4, s);
}

void readr(char s)
{
    char tmp1[50], tmp2[50], tmp3[50];
    scanf("%s %s %s", tmp1, tmp2, tmp3);
    int x1, y1, x2, y2, x3, y3;
    sscanf(tmp1, "(%d,%d)", &x1, &y1);
    sscanf(tmp2, "(%d,%d)", &x2, &y2);
    sscanf(tmp3, "(%d,%d)", &x3, &y3);
    point p[4];
    p[0] = point(x1, y1);
    p[1] = point(x2, y2);
    p[2] = point(x3, y3);

    p[3] = point(p[2].x + (p[0].x - p[1].x), p[2].y - (p[1].y - p[0].y));
    L[++lcnt] = line(p[0], p[1], s);
    L[++lcnt] = line(p[1], p[2], s);
    L[++lcnt] = line(p[2], p[3], s);
    L[++lcnt] = line(p[0], p[3], s);
}

void readl(char s)
{
    char tmp1[50], tmp2[50];
    scanf("%s %s", tmp1, tmp2);
    int x1, y1, x2, y2;
    sscanf(tmp1, "(%d,%d)", &x1, &y1);
    sscanf(tmp2, "(%d,%d)", &x2, &y2);
    point a = point(x1, y1);
    point b = point(x2, y2);
    L[++lcnt] = line(a, b,s);
}

void readt(char s)
{
    char tmp1[50], tmp2[50], tmp3[50];
    scanf("%s %s %s", tmp1, tmp2, tmp3);
    int x1, y1, x2, y2, x3, y3;
    sscanf(tmp1, "(%d,%d)", &x1, &y1);
    sscanf(tmp2, "(%d,%d)", &x2, &y2);
    sscanf(tmp3, "(%d,%d)", &x3, &y3);
    point a = point(x1, y1);
    point b = point(x2, y2);
    point c = point(x3, y3);
    L[++lcnt] = line(a, b,s);
    L[++lcnt] = line(a, c,s);
    L[++lcnt] = line(b, c,s);
}

void readp(char s)
{
    int num;
    scanf("%d", &num);
    int x1, y1;
    char tmp1[50];
    scanf("%s", tmp1);
    sscanf(tmp1, "(%d,%d)", &x1, &y1);
    int beforex = x1, beforey = y1;
    int nowx, nowy;
    for (int i = 2;i <= num;i++)
    {
        scanf("%s", tmp1);
        sscanf(tmp1, "(%d,%d)", &nowx, &nowy);
        L[++lcnt] = line(point(beforex, beforey), point(nowx, nowy),s);
        beforex = nowx;
        beforey = nowy;
    }
    L[++lcnt] = line(point(x1, y1), point(nowx, nowy), s);
}
bool col[30][30];
bool have[30];
bool read(char s, bool change)
{
    if (change)
    {
        lcnt = 0;
        memset(col, 0, sizeof(col));
        memset(have, 0, sizeof(have));
    }

    char str[5];
    scanf("%s", str);
    if (str[0] == s)return 0;
    have[str[0] - 'A'] = 1;
    string type;
    cin >> type;
    if (type[0] == 's')
        reads(str[0]);
    else if (type[0] == 'r')
        readr(str[0]);
    else if (type[0] == 'l')
        readl(str[0]);
    else if (type[0] == 't')
        readt(str[0]);
    else if (type[0] == 'p')
        readp(str[0]);
    return 1;
}

double xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

int dots_inline(point p1, point p2, point p3)
{
    return zero(xmult(p1, p2, p3));
}

int same_side(point p1, point p2, line l)
{
    return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) > eps;
}

int dot_online_in(point p, line l)
{
    return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x)*(l.b.x - p.x) < eps && (l.a.y - p.y)*(l.b.y - p.y) < eps;
}

int intersect_in(line u, line v)
{
    if (!dots_inline(u.a, u.b, v.a) || !dots_inline(u.a, u.b, v.b))
        return !same_side(u.a, u.b, v) && !same_side(v.a, v.b, u);
    return dot_online_in(u.a, v) || dot_online_in(u.b, v) || dot_online_in(v.a, u) || dot_online_in(v.b, u);
}

int check(int num,int &flag)
{
    int cnt = 0;
    for (int i = 0;i < 26;i++)if (col[num][i])cnt++;
    if (cnt == 1)
        flag = 1;
    else if (cnt == 2)
        flag = 2;
    else flag = 3;
    for (int i = 25;i >= 0;i--)if (col[num][i])
        return i;
    return -1;
}

void solve()
{
    for(int i=1;i<=lcnt;i++)
        for (int j = i + 1;j <= lcnt;j++)if(L[i].s!=L[j].s)
        {
            if (intersect_in(L[i], L[j]))
            {
                col[L[i].s-'A'][L[j].s-'A'] = col[L[j].s-'A'][L[i].s-'A'] = 1;
            }
        }
    for (int i = 0;i < 26;i++)if (have[i])
    {
        printf("%c", 'A' + i);
        int flag;
        int last = check(i,flag);
        if (last==-1)
            puts(" has no intersections");
        else
        {
            printf(" intersects with");
            if (flag == 1)
            {
                printf(" %c\n", last + 'A');
            }
            else if (flag == 2)
            {
                for (int j = 0;j <= last;j++)
                {
                    if (!col[i][j])
                        continue;
                    char tmp = j + 'A';
                    if (j != last)
                        printf(" %c", tmp);
                    else
                        printf(" and %c\n", tmp);
                }
            }
            else
            {
                for (int j = 0;j <= last;j++)
                {
                    if (!col[i][j])
                        continue;
                    char tmp = j + 'A';
                    if (j != last)
                        printf(" %c,", tmp);
                    else
                        printf(" and %c\n", tmp);
                }
            }
        }
    }

}

int main()
{
    string name;
    while (read('.', true))
    {
        while (read('-', false));
        solve();
        puts("");
    }


}

N - A Round Peg in a Ground Hole
一道模板题。先用叉积判断是不是凸包,再判断圆心是否在多边形内部,再用距离判断多边形是否把圆包围。

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

const int MAXN = 1e3 + 7;
const double EPS = 1e-8;
const double oo = 1e10 + 7;

struct Point
{
    double x, y;
    Point(double x = 0, double y = 0) :x(x), y(y) {}
    Point operator - (const Point &tmp)const {
        return Point(x - tmp.x, y - tmp.y);
    }
    double operator ^(const Point &tmp)const {
        return x*tmp.y - y*tmp.x;
    }
    double operator *(const Point &tmp)const {
        return x*tmp.x + y*tmp.y;
    }
};
double Dist(Point a, Point b)
{///两点间的距离
    return sqrt((a - b)*(a - b));
}
int Sign(double t)
{
    if (t > EPS)return 1;
    if (fabs(t) < EPS)return 0;
    return -1;///负数
}
struct Segment
{
    Point S, E;
    Segment(Point S = 0, Point E = 0) :S(S), E(E) {}
    bool OnSeg(const Point &p)
    {///点是否在线段上
        if (Sign((S - E) ^ (p - E)) == 0)///共线
            if (Sign((p.x - S.x)*(p.x - E.x)) <= 0)///位于线段的中间或者端点
                if (Sign((p.y - S.y)*(p.y - E.y)) <= 0)
                    return true;
        return false;
    }
    bool Inter(const Segment &tmp)
    {///只考虑完全相交的情况
        return Sign((S - E) ^ (tmp.S - E)) * Sign((S - E) ^ (tmp.E - E)) == -1;
    }
    Point NearPoint(const Point &p)
    {///点到线段最近的点
        Point res;
        double r = ((E - S)*(p - S)) / ((E - S)*(E - S));

        if (r > EPS && (1.0 - r) > EPS)
        {///点在线段的投影在线段上
            res.x = S.x + r * (E.x - S.x);
            res.y = S.y + r * (E.y - S.y);
        }
        else
        {///求离最近的端点
            if (Dist(p, S) < Dist(p, E))
                res = S;
            else
                res = E;
        }

        return res;
    }
};
struct Poly
{
    int N;
    Point vertex[MAXN];

    bool IsConvex()
    {///判断是否是凸多边形,可以共线
        int vis[3] = { 0 };
        for (int i = 0; i<N; i++)
        {///如果同时出现整数和负数,说明存在凹的
            int k = Sign((vertex[(i + 1) % N] - vertex[i]) ^ (vertex[(i + 2) % N] - vertex[i]));
            vis[k + 1] = 1;

            if (vis[0] && vis[2])
                return false;
        }
        return true;
    }
    int InPoly(const Point &Q)
    {///判断点Q是否在多边形内,射线法,奇数在内,偶数在外
     ///在圆上返回0, 圆外-1, 圆内 1
        Segment ray(Point(-oo, Q.y), Q);///构造射线的最远处
        int cnt = 0;///统计相交的边数

        for (int i = 0; i<N; i++)
        {
            Segment edge(vertex[i], vertex[(i + 1) % N]);

            if (edge.OnSeg(Q) == true)
                return 0;///点在边上

            if (ray.OnSeg(vertex[i]) == true)
            {///如果相交连接点,那么取y值小的点
                if (vertex[(i + 1) % N].y - vertex[i].y > EPS)
                    cnt++;
            }
            else if (ray.OnSeg(vertex[(i + 1) % N]) == true)
            {
                if (vertex[i].y - vertex[(i + 1) % N].y > EPS)
                    cnt++;
            }
            else if (ray.Inter(edge) && edge.Inter(ray))
                cnt++;
        }

        if (cnt % 2)
            return 1;
        else
            return -1;
    }
};
struct Circle
{
    Point center;///圆心
    double R;///半径
};

bool Find(Poly &a, Circle &c)
{///判断圆是否在多边形内
    if (a.InPoly(c.center) == -1)
        return false;///如果圆心在多边形外面

    for (int i = 0; i<a.N; i++)
    {
        Segment edge(a.vertex[i], a.vertex[(i + 1) % a.N]);
        double len = Dist(c.center, edge.NearPoint(c.center));

        if (Sign(len - c.R) < 0)
            return false;
    }

    return true;
}

int main()
{
    Poly a;///定义多边形
    Circle c;///定义圆

    while (scanf("%d", &a.N) != EOF && a.N > 2)
    {
        scanf("%lf%lf%lf", &c.R, &c.center.x, &c.center.y);
        for (int i = 0; i<a.N; i++)
            scanf("%lf%lf", &a.vertex[i].x, &a.vertex[i].y);

        if (a.IsConvex() == false)
            printf("HOLE IS ILL-FORMED\n");
        else if (Find(a, c) == false)
            printf("PEG WILL NOT FIT\n");
        else
            printf("PEG WILL FIT\n");
    }

    return 0;
}

之后会把整理的模板贴上来。

1 字符串处理 5 1.1 KMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2 e-KMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.3 Manacher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.4 AC 自动机 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.5 后缀数组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.5.1 DA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.5.2 DC3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.6 后缀自动机 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.6.1 基本函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 1.6.2 例题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.7 字符串 hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2 数学 25 2.1 素数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.1.1 素数筛选(判断 <MAXN 的数是否素数) . . . . . . . . . . . . . . . . 25 2.1.2 素数筛选(筛选出小于等于 MAXN 的素数) . . . . . . . . . . . . . . . 25 2.1.3 大区间素数筛选(POJ 2689) . . . . . . . . . . . . . . . . . . . . . . . 25 2.2 素数筛选和合数分解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.3 扩展欧几里得算法(求 ax+by=gcd 的解以及逆元) . . . . . . . . . . . . . . . 27 2.4 求逆元 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4.1 扩展欧几里德法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4.2 简洁写法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4.3 利用欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.5 模线性方程组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.6 随机素数测试和大数分解 (POJ 1811) . . . . . . . . . . . . . . . . . . . . . . . 29 2.7 欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7.1 分解质因素求欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7.2 筛法欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7.3 求单个数的欧拉函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7.4 线性筛(同时得到欧拉函数和素数表) . . . . . . . . . . . . . . . . . . 32 2.8 高斯消元(浮点数) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.9 FFT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.10 高斯消元法求方程组的解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.10.1 一类开关问题,对 2 取模的 01 方程组 . . . . . . . . . . . . . . . . . . . 37 2.10.2 解同余方程组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 2.11 整数拆分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 2.12 求 A B 的约数之和对 MOD 取模 . . . . . . . . . . . . . . . . . . . . . . . . . . 43 2.13 莫比乌斯反演 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.13.1 莫比乌斯函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.13.2 例题:BZOJ2301 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 2.14 Baby-Step Giant-Step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 2.15 自适应 simpson 积分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 2.16 斐波那契数列取模循环节 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 2.17 原根 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 2.18 快速数论变换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 2.18.1 HDU4656 卷积取模 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 2.19 其它公式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 2.19.1 Polya . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 kuangbin 1 ACM Template of kuangbin 3 数据结构 56 3.1 划分树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.2 RMQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.2.1 一维 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.2.2 二维 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 3.3 树链剖分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.3.1 点权 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.3.2 边权 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 3.4 伸展树(splay tree) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 3.4.1 例题:HDU1890 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 3.4.2 例题:HDU3726 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 3.5 动态树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 3.5.1 SPOJQTREE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 3.5.2 SPOJQTREE2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 3.5.3 SPOJQTREE4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 3.5.4 SPOJQTREE5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 3.5.5 SPOJQTREE6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 3.5.6 SPOJQTREE7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 3.5.7 HDU4010 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 3.6 主席树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 3.6.1 查询区间多少个不同的数 . . . . . . . . . . . . . . . . . . . . . . . . . . 95 3.6.2 静态区间第 k 大 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 3.6.3 树上路径点权第 k 大 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 3.6.4 动态第 k 大 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 3.7 Treap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 3.8 KD 树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 3.8.1 HDU4347 K 近邻 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 3.8.2 CF44G . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 3.8.3 HDU4742 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 3.9 替罪羊树 (ScapeGoat Tree) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 3.9.1 CF455D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 3.10 动态 KD 树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 3.11 树套树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 3.11.1 替罪羊树套 splay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4 图论 130 4.1 最短路 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.1.1 Dijkstra 单源最短路 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.1.2 Dijkstra 算法 + 堆优化 . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.1.3 单源最短路 bellman_ford 算法 . . . . . . . . . . . . . . . . . . . . . . . 131 4.1.4 单源最短路 SPFA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 4.2 最小生成树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 4.2.1 Prim 算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 4.2.2 Kruskal 算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 4.3 次小生成树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 4.4 有向图的强连通分量 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 4.4.1 Tarjan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 4.4.2 Kosaraju . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 4.5 图的割点、桥和双连通分支的基本概念 . . . . . . . . . . . . . . . . . . . . . . . 138 4.6 割点与桥 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 4.6.1 模板 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 kuangbin 2 ACM Template of kuangbin 4.6.2 调用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 4.7 边双连通分支 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 4.8 点双连通分支 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 4.9 最小树形图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 4.10 二分图匹配 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 4.10.1 邻接矩阵(匈牙利算法) . . . . . . . . . . . . . . . . . . . . . . . . . . 149 4.10.2 邻接表(匈牙利算法) . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 4.10.3 Hopcroft-Karp 算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 4.11 二分图多重匹配 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 4.12 二分图最大权匹配(KM 算法) . . . . . . . . . . . . . . . . . . . . . . . . . . 153 4.13 一般图匹配带花树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 4.14 一般图最大加权匹配 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 4.15 生成树计数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 4.16 最大流 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 4.16.1 SAP 邻接矩阵形式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 4.16.2 SAP 邻接矩阵形式 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 4.16.3 ISAP 邻接表形式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 4.16.4 ISAP+bfs 初始化 + 栈优化 . . . . . . . . . . . . . . . . . . . . . . . . . 165 4.16.5 dinic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 4.16.6 最大流判断多解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 4.17 最小费用最大流 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 4.17.1 SPFA 版费用流 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 4.17.2 zkw 费用流 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 4.18 2-SAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 4.18.1 染色法(可以得到字典序最小的解) . . . . . . . . . . . . . . . . . . . . 172 4.18.2 强连通缩点法(拓扑排序只能得到任意解) . . . . . . . . . . . . . . . . 173 4.19 曼哈顿最小生成树 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 4.20 LCA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 4.20.1 dfs+ST 在线算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 4.20.2 离线 Tarjan 算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 4.20.3 LCA 倍增法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 4.21 欧拉路 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 4.21.1 有向图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 4.21.2 无向图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 4.21.3 混合图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 4.22 树分治 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 4.22.1 点分治 -HDU5016 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 4.22.2 * 点分治 -HDU4918 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 4.22.3 链分治 -HDU5039 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 5 搜索 205 5.1 Dancing Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 5.1.1 精确覆盖 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 5.1.2 可重复覆盖 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 5.2 八数码 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 5.2.1 HDU1043 反向搜索 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 6 动态规划 212 6.1 最长上升子序列 O(nlogn) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 6.2 背包 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 6.3 插头 DP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 kuangbin 3 ACM Template of kuangbin 6.3.1 HDU 4285 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 7 计算几何 218 7.1 二维几何 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 7.2 三维几何 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 7.3 平面最近点对 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 7.4 三维凸包 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 7.4.1 HDU4273 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 8 其他 249 8.1 高精度 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 8.2 完全高精度 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 8.3 strtok 和 sscanf 结合输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 8.4 解决爆栈,手动加栈 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 8.5 STL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 8.5.1 优先队列 priority_queue . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 8.5.2 set 和 multiset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 8.6 输入输出外挂 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 8.7 莫队算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 8.7.1 分块 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 8.7.2 Manhattan MST 的 dfs 顺序求解 . . . . . . . . . . . . . . . . . . . . . . 260 8.8 VIM 配置 .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值