异色三角剖分校验 内角排序

http://acm.zjnu.edu.cn/CLanguage/contests/1167/problems/1002.html
(可以在弊校OJ提交)

题意

输入一个可能错误的三角剖分(n阶凸多边形,内部n - 3条对角线)。
每条边的边权是三种颜色之一。

校验1:这是一个正确的三角剖分
校验2:这个三角剖分的每个单元三角形都是异色三角形。

思路

如果三角剖分正确,内部每个单元三角形的内角,都对应一条边。
(反过来,一条对角线对应两个内角,一条轮廓边对应一个内角)
如果存在连线出错了,必定会产生内部多边形不是三角形的情况。这样内角对应的边会找不到。
如果每个三角形都是异色三角形,那么每个内角的两个夹角边异色。

所以只要枚举内角,检查每个内角,对边是否存在,夹角边是否异色。

如何枚举内角?

把这个几何图形建成无向图图论模型,我们希望每个点的邻接表中的编号都是顺时针或者逆时针的,那么每次枚举邻边就代表这个图形中的内角。

考虑在邻接表排序的时候,把当前编号作为最小值,重新映射所有编号(取模)。这样排序以后就可以自然地从n - 1 枚举下一个是 0 1 2
以下是逆时针的排序做法:
不理解lambda,可以写个比较函数,把i作为全局变量传递。

 for (int i = 0; i < n; ++i) {
     sort(g[i].begin(), g[i].end(), [&i](edge l, edge r) {
         return (l.id - i + n) % n < (r.id - i + n) % n;
     });
 }

代码


const int MAXN = 2e5 + 59;
using pii = pair<int, int>;

int n;
char s[MAXN];
vector<pii> g[MAXN];
set<pii> has;

void solve(int kaseId = -1) {
    int _ = 0;
    cin >> _;
    cin >> n >> s;

    bool check1 = true;
    bool check2 = true;

    for (int i = 0; i < n - 3; ++i) {
        int u, v, c;
        cin >> u >> v >> c;
        u--, v--;
        g[u].emplace_back(v, c);
        g[v].emplace_back(u, c);
        has.emplace(u, v);
    }

    for (int i = 0; i < n; ++i) {
        int u = i;
        int v = (i + 1) % n;
        int c = s[i] - '0';
        g[u].emplace_back(v, c);
        g[v].emplace_back(u, c);
    }

    for (int i = 0; i < n; ++i) {
        sort(g[i].begin(), g[i].end(), [&i](pii l, pii r) {
            return (l.first - i + n) % n < (r.first - i + n) % n;
        });
    }

    for (int u = 0; check1 && u < n; ++u) {
        int len = int(g[u].size());
        for (int i = 0, j = 1; j < len; ++i, ++j) {
            int vi = g[u][i].first;
            int vj = g[u][j].first;
            int ci = g[u][i].second;
            int cj = g[u][j].second;

            if ((vi + 1) % n != vj &&
                (vj + 1) % n != vi &&   // 轮廓边必然存在,跳过。
                has.count(pii{vi, vj}) == 0 &&
                has.count(pii{vj, vi}) == 0) {
                check1 = false;
                break;
            }
            
            if (ci == cj) {
                check2 = false;
            }
        }
    }

    if (!check1) {
        cout << "neispravna triangulacija\n";
    } else if (!check2) {
        cout << "neispravno bojenje\n";
    } else {
        cout << "tocno\n";
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值