【问题标题】:One topcoder puzzle about IntersectingConvexHull一个关于 IntersectingConvexHull 的 topcoder 谜题
【发布时间】:2016-09-20 00:16:51
【问题描述】:

我在四个小时前第一次问了这个问题。其实这个问题我搜索了6个多小时还是看不懂。

这个问题是关于通过给你 x[n] 和 y[n] 来给你 n 分。您应该找到这些点的两个子集,它们的凸包相交。您的回答应该是满足上述规则的案例数。

给定平面上的有限集合 S。对于每个有效的 i, 其中一个点具有坐标 (x[i], y[i])。积分都是 不同的,没有三个是共线的。

下面,CH(s) 表示集合 s 的凸包:即 包含集合 s 的所有凸多边形中的最小的。我们说 如果满足以下条件,则有序对 (s1, s2) 很有趣 满意:

1.s1 是 S 的子集

2.s2 是 S 的子集

3. 集合 s1 和 s2 是不相交的(即它们没有共同的元素)

4. 凸包 CH(s1) 和 CH(s2) 的交点具有正面积注意,S 中的某些点可能仍未使用(即, 它们既不在 s1 中,也不在 s2 中)。你被给予 所有点的坐标:s x 和 y。请计算并返回 有趣的集合对的数量,模 10^9 + 7。

例子

{1,0,-1,-1,0,1} {1,2,1,-1,-2,-1}

返回:14

我们有 14 个 解决方案:

s1 = {0,1,3},s2 = {2,4,5} s1 = {0,2,3},s2 = {1,4,5} s1 = {0,1,4},s2 = {2,3,5} s1 = {0,2,4},s2 = {1,3,5} s1 = {1,2,4},s2 = {0,3,5} s1 = {0,3,4},s2 = {1,2,5} s1 = {1,3,4},s2 = {0,2,5} s1 = {0,2,5},s2 = {1,3,4} s1 = {1,2,5},s2 = {0,3,4} s1 = {0,3,5},s2 = {1,2,4} s1 = {1,3,5},s2 = {0,2,4} s1 = {2,3,5},s2 = {0,1,4} s1 = {1,4,5},s2 = {0,2,3} s1 = {2,4,5},s2 = {0,1,3}

有很多我无法理解的解决方案,以下是其中之一。例如,ccw 是干什么用的?结果由两部分组成,为什么? 能否给我一些算法名称,一些关键字也可以,我可以在google上详细搜索一下?

这是解决此问题的一个示例代码:

#include <vector>
#include <iostream>

using namespace std;
const long long mod=1000000007ll;
struct IntersectingConvexHull{
    public:
        int count(vector<int> x, vector<int> y){
            int n = x.size();
            long long P2[110];
            P2[0]=1ll;
            for(int i=1;i<=n;i++){
                P2[i]=P2[i-1]*2%mod;
            }
            long long C[110][110];
            for(int i=0;i<=n;i++){
                C[i][0]=C[i][i]=1ll;
                for(int j=1;j<i;j++){
                    C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
                }
            }
            long long X[100],Y[100];
            for(int i=0;i<=n;i++){
                X[i]=x[i];
                Y[i]=y[i];
            }
            long long ans=0;
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(i==j)continue;
    
                    int c1=0,c2=0;
                    for(int k=0;k<n;k++){
                        if(k==i||k==j){
                            continue;
                        }
                        long long ccw=(X[i]-X[k])*(Y[j]-Y[k])-(Y[i]-Y[k])*(X[j]-X[k]);
                        if(ccw<0){
                            c1++;
                        }
                        else{
                            c2++;
                        }
                    }
                    if(c1>=2&&c2>=2){
                        ans+=((P2[c1]+mod-c1-1)%mod)*((P2[c2]+mod-c2-1)%mod)%mod;
                        ans%=mod;
                    }
                }
            }
            long long A=0ll;
            for(int i=3;i<=n;i++){
                for(int j=3;j<=n-i;j++){
                    A+=C[n][i]*C[n-i][j]%mod;
                    A%=mod;
                }
            }
            return (A+mod-ans)%mod;

        }
};

【问题讨论】:

  • 请不要张贴图片作为代码。而是发布代码。
  • 但由于网站限制,我无法复制它们。
  • 然后通过查看图像手动输入代码。
  • 好的,等几分钟。
  • 我又打了一遍

标签: c++ algorithm


【解决方案1】:

两个集合必须至少具有三个点,船体的交点才能具有非零面积。该代码计算满足此标准的分区数减去交叉面积为零的分区数。 (P2 是 2 的幂。C 是二项式系数。)

当且仅当有一条线将两个凸包分开时,两个凸包的交集面积为零 (Hyperplane separation theorem)。我认为我们需要对这个结果进行扩展,实际上,(在正确的假设下)恰好有两条线将船体分开并接触两者。

最后一个循环计算被减数。之前的计算减数是考虑几何因素的地方。代码循环遍历所有点对,并考虑通过它们的线,通过符号面积测试计算每边的点数。它增加了从每一侧选择两个或多个点的方法的数量,从而确保,如果我们将一对中的第一个点包含在一个外壳中,并将该对中的第二个点包含在另一个外壳中,我们会得到两个外壳由线支撑并由线分隔。

我不知道这段代码如何处理退化的输入(两个重复点,三个共线点)。

【讨论】:

    猜你喜欢
    • 2013-06-17
    • 2016-04-01
    • 1970-01-01
    • 2017-11-02
    • 2011-09-17
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多