• [BZOJ 1804] Flood


    Link:

    BZOJ 1804 传送门

    Solution:

    不容易啊,第一道完全自己A掉的IOI题目.....

    算法思想其实很简单:

    模拟缩减的过程即可

    将每条边转为2条有向边,每次找到最左边的边,沿着最外圈走一周,并将走过的边打上$vis$标记

    最后那些正向和反向都被走过的边就是能留下的边(最后形成链的边)

    难点在于如何实现在最外层走一周:

    由于这是一个平面图,我们对每个点只要记录上下左右四个方向的边即可

    保证是顺时针转,因此尽量往左边走就能满足最外圈这个条件

    (注意对$vis$数组更新的位置,否则可能在遇到链时死循环)

    其实还有一种不带$log$的做法:

    平面图转化为对偶图,$bfs$每条边到边界的距离

    如果两边的距离相等,这条边就计入答案(难点在建图)

    待填坑

    Code:

    #include <bits/stdc++.h>
     
    using namespace std;
    typedef pair<int,int> P;
    #define X first
    #define Y second
    const int MAXN=4e5+10;
     
    P nd[MAXN],tp[MAXN];
    int n,m,dir[MAXN][4],cnt[MAXN][4],vis[MAXN][4],res=0;
    int tot=0,tdir[MAXN];
    struct edge{int x,y,dir;} e[2*MAXN];
    bool cmp(edge a,edge b) //对边的排序
    {
        if(nd[a.x].X==nd[b.x].X)
            if((a.dir==0 || a.dir==2) && (b.dir==1 || b.dir==3)) return true;
            else if((a.dir==1 || a.dir==3) && (b.dir==0 || b.dir==2)) return false;
        return nd[a.x].X<nd[b.x].X;
    }
     
    void add_edge(int a,int b,int id)
    {
        if(nd[a].X==nd[b].X)
            if(nd[a].Y<nd[b].Y) dir[a][0]=b,dir[b][2]=a,e[id].dir=0;
            else dir[a][2]=b,dir[b][0]=a,e[id].dir=2;
        else
            if(nd[a].X<nd[b].X) dir[a][1]=b,dir[b][3]=a,e[id].dir=1;
            else dir[a][3]=b,dir[b][1]=a,e[id].dir=3;;
    }
     
    int Back(int x){return (x+2)%4;}
    int Left(int x){return (x+3)%4;}
    int Right(int x){return (x+1)%4;}
    void Travel(int id)
    {
        int cur=e[id].y,d=e[id].dir,pre=e[id].x;cnt[pre][d]++;
        tot=1;tp[tot]=P(pre,cur);tdir[tot]=d;
        while(cur!=e[id].x)
        {        
            d=Left(d); //尽量往左走
            while(!dir[cur][d] || vis[cur][d]) d=Right(d);
            pre=cur;cur=dir[cur][d];cnt[pre][d]++;
            tp[++tot]=P(pre,cur);tdir[tot]=d;
        }
        for(int i=1;i<=tot;i++) //一定要最后一起打vis标记,否则可能死循环
            vis[tp[i].X][tdir[i]]=vis[tp[i].Y][Back(tdir[i])]=true;
    }
     
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&nd[i].X,&nd[i].Y);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&e[i].x,&e[i].y);
            if(nd[e[i].x].X>nd[e[i].y].X) swap(e[i].x,e[i].y);
            if(nd[e[i].x].Y>nd[e[i].y].Y) swap(e[i].x,e[i].y);
            add_edge(e[i].x,e[i].y,i);
        }
        
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=m;i++)
        {
            if(vis[e[i].x][e[i].dir]) continue; //已走过的边
            Travel(i);
        }
        for(int i=1;i<=m;i++)
            if(cnt[e[i].x][e[i].dir] && cnt[e[i].y][Back(e[i].dir)]) res++;
        printf("%d",res);
        return 0;
    }

    Review:

    遇到平面图时(保证边两两不相交),一定要考虑其对偶图

  • 相关阅读:
    mysqldump 导出数据库为DBname的表名为Tname的表结构 导出数据库的所有表的表结构
    mysqldump 备份某张表 Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions,
    nfs missing codepage or helper program, or other error
    date 增加一个小时 减少一个小时
    mysqldump 备份单个数据库
    mysql删除账户
    怎么删除某个用户的所有帖子?
    mongodb删除重复数据
    ReSharper2018破解详细方法
    激活windows和office
  • 原文地址:https://www.cnblogs.com/newera/p/9141827.html
Copyright © 2020-2023  润新知