• 【bzoj3630】[JLOI2014]镜面通道 对偶图+计算几何+网络流最小割


    题目描述

    在一个二维平面上,有一个镜面通道,由镜面AC,BD组成,AC,BD长度相等,且都平行于x轴,B位于(0,0)。通道中有n个外表面为镜面的光学元件,光学元件α为圆形,光学元件β为矩形(这些元件可以与其他元件和通道有交集,具体看下图)。光线可以在AB上任一点以任意角度射入通道,光线不会发生削弱。当出现元件与元件,元件和通道刚好接触的情况视为光线无法透过(比如两圆相切)。现在给出通道中所有元件的信息(α元件包括圆心坐标和半径xi,yi,ri,β元件包括左下角和右上角坐标x1,y1,x2,y2)

    如上图,S到T便是一条合法线路。

    当然,显然存在光线无法透过的情况,现在交给你一个艰巨的任务,请求出至少拿走多少个光学元件后,存在一条光线线路可以从CD射出。

    下面举例说明:

    现在假设,取走中间那个矩形,那么就可以构造出一条穿过通道的光路,如图中的S到T。

    输入

    第一行包含两个整数,x,y,表示C点坐标

    第二行包含一个数字,n,表示有n个光学元件

    接下来n行

    第一个数字如果是1,表示元件α,后面会有三个整数xi,yi,ri分别表示圆心坐标和半径

    第一个数字如果是2,表示元件β,后面会有四个整数x1,y1,x2,y2分别表示左下角和右上角坐标(矩形都平行,垂直于坐标轴)

    输出

    输出包含一行,至少需要拿走的光学元件个数m

    样例输入

    1000 100
    6
    1 500 0 50
    2 10 10 20 100
    2 100 10 200 100
    2 300 10 400 100
    2 500 10 600 100
    2 700 0 800 100

    样例输出

    2


    题解

    对偶图+计算几何+网络流最小割

    首先有个神奇的物理学结论:水能通过的地方光也一定能通过。

    因此直接判定左右通道是否连通即可。而和 bzoj3007 类似,左右连通意味着对偶图上下不连通。

    所以问题转化为去掉最少的点使得上下不连通。这显然是个最小割问题。

    拆点,如果两个元件相交,则互相连出点->入点的边,容量为inf;每个点的入点->出点,容量为1。最小割即为答案。

    不过有点恶心的是原件相交的判定,需要耐心= =

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 610
    #define M 400010
    using namespace std;
    typedef long long ll;
    const int inf = 1 << 30;
    queue<int> q;
    int flag[N] , a[N] , b[N] , c[N] , d[N] , head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N];
    void add(int x , int y , int z)
    {
        to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
        to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
    }
    bool bfs()
    {
        int x , i;
        memset(dis , 0 , sizeof(dis));
        while(!q.empty()) q.pop();
        dis[s] = 1 , q.push(s);
        while(!q.empty())
        {
            x = q.front() , q.pop();
            for(i = head[x] ; i ; i = next[i])
            {
                if(val[i] && !dis[to[i]])
                {
                    dis[to[i]] = dis[x] + 1;
                    if(to[i] == t) return 1;
                    q.push(to[i]);
                }
            }
        }
        return 0;
    }
    int dinic(int x , int low)
    {
        if(x == t) return low;
        int temp = low , i , k;
        for(i = head[x] ; i ; i = next[i])
        {
            if(val[i] && dis[to[i]] == dis[x] + 1)
            {
                k = dinic(to[i] , min(temp , val[i]));
                if(!k) dis[to[i]] = 0;
                val[i] -= k , val[i ^ 1] += k;
                if(!(temp -= k)) break;
            }
        }
        return low - temp;
    }
    ll calc(int x , int y)
    {
        return (ll)x * x + (ll)y * y;
    }
    bool judge(int x , int y)
    {
        if(flag[x] + flag[y] == 2) return calc(a[x] - a[y] , b[x] - b[y]) <= (ll)(c[x] + c[y]) * (c[x] + c[y]);
        else if(flag[x] + flag[y] == 3)
        {
            if(flag[x] == 2) swap(x , y);
            if(calc(a[x] - a[y] , b[x] - b[y]) <= (ll)c[x] * c[x]) return 1;
            if(calc(a[x] - a[y] , b[x] - d[y]) <= (ll)c[x] * c[x]) return 1;
            if(calc(a[x] - c[y] , b[x] - b[y]) <= (ll)c[x] * c[x]) return 1;
            if(calc(a[x] - c[y] , b[x] - d[y]) <= (ll)c[x] * c[x]) return 1;
            if(abs(a[x] - a[y]) <= c[x] && b[x] >= b[y] && b[x] <= d[y]) return 1;
            if(abs(a[x] - c[y]) <= c[x] && b[x] >= b[y] && b[x] <= d[y]) return 1;
            if(abs(b[x] - b[y]) <= c[x] && a[x] >= a[y] && a[x] <= c[y]) return 1;
            if(abs(b[x] - d[y]) <= c[x] && a[x] >= a[y] && a[x] <= c[y]) return 1;
            return 0;
        }
        else
        {
            if(a[x] >= a[y] && a[x] <= c[y] && b[y] >= b[x] && b[y] <= d[x]) return 1;
            if(a[x] >= a[y] && a[x] <= c[y] && d[y] >= b[x] && d[y] <= d[x]) return 1;
            if(b[x] >= b[y] && b[x] <= d[y] && a[y] >= a[x] && a[y] <= c[x]) return 1;
            if(b[x] >= b[y] && b[x] <= d[y] && c[y] >= a[x] && c[y] <= c[x]) return 1;
            if(c[x] >= a[y] && c[x] <= c[y] && b[y] >= b[x] && b[y] <= d[x]) return 1;
            if(c[x] >= a[y] && c[x] <= c[y] && d[y] >= b[x] && d[y] <= d[x]) return 1;
            if(d[x] >= b[y] && d[x] <= d[y] && a[y] >= a[x] && a[y] <= c[x]) return 1;
            if(d[x] >= b[y] && d[x] <= d[y] && c[y] >= a[x] && c[y] <= c[x]) return 1;
            return 0;
        }
        return 0;
    }
    int main()
    {
        int h , n , i , j , ans = 0;
        scanf("%*d%d%d" , &h , &n) , s = 0 , t = 2 * n + 2;
        for(i = 1 ; i <= n ; i ++ )
        {
            scanf("%d%d%d%d" , &flag[i] , &a[i] , &b[i] , &c[i]);
            add(i + n + 1 , i , 1);
            if(flag[i] == 1)
            {
                if(b[i] + c[i] >= h) add(s , i + n + 1 , inf);
                if(b[i] - c[i] <= 0) add(i , t , inf);
            }
            if(flag[i] == 2)
            {
                scanf("%d" , &d[i]);
                if(d[i] >= h) add(s , i + n + 1 , inf);
                if(b[i] <= 0) add(i , t , inf);
            }
            for(j = 1 ; j < i ; j ++ )
                if(judge(i , j))
                    add(i , j + n + 1 , inf) , add(j , i + n + 1 , inf);
        }
        while(bfs()) ans += dinic(s , inf);
        printf("%d
    " , ans);
        return 0;
    }
    

     

  • 相关阅读:
    不写代码能实现APP消息推送吗
    如何让智能设备接入天猫精灵,实现语音控制功能
    给GoKit3(STM32)装一块N102,在家就能体验NB-IoT开发啦
    ESP8266 NodeMcu机智云SOC方案开发经验分享
    利用map和reduce编写一个str2float函数
    代码学习(1)
    箱线图boxplot()的绘制
    mysql远程访问数据库的问题解决
    codeforces 596 C. p-binary
    主席树的妙用——Just h-index
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7392175.html
Copyright © 2020-2023  润新知