zoukankan      html  css  js  c++  java
  • 【题解】 CF437E The Child and Polygon 计算几何+dp

    Legend

    Link ( extrm{to Codeforces})

    给定一个 (n) 个点的简单多边形,求三角剖分数目。

    (3 le n le 200)

    Editorial

    做题做傻了,一个显然的区间 ( m{dp}) 都没看出来。

    显然设 (dp_{l,r}) 表示使用了编号 (l sim r) 的所有点进行三角剖分的方案数。

    转移 (dp_{l,r} = sum_{l < k < r} dp_{l,k} imes dp{k,r})

    答案就是 (dp_{1,n})

    显然有如下情况的是不合法的状态,不能转移:

    • (l o r) 的连边会穿过多边形的任何部位。
    • (l o r) 的连边在多边形外部。

    第一个判断就直接判断,第二个有一个神仙的判断方法。

    这条边会把多边形按下标分成两个部分,如果这条边在外部并与多边形无交则一定会增加多边形的面积。

    不过其实这两个有一个共同的判断方法:

    在枚举 (k) 的时候看 (k) 是不是凹进去的就好了,凹进去就不合法。

    Code

    判断部分写得非常丑……看完题解才发现有这么简单的判断方法。

    但是毕竟写都写完了,还是不改了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define LL long long
    
    const int MX = 200 + 23;
    const LL MOD = 1e9 + 7;
    
    struct VECTOR{
    	LL x ,y;
    	VECTOR(LL X = 0 ,LL Y = 0){x = X ,y = Y;}
    	VECTOR operator +(const VECTOR &B)const{return VECTOR(x + B.x ,y + B.y);}
    	VECTOR operator -(const VECTOR &B)const{return VECTOR(x - B.x ,y - B.y);}
    	LL operator *(const VECTOR &B)const{return x * B.y - y * B.x;}
    	bool operator ==(const VECTOR &B)const{return x == B.x && y == B.y;}
    	void Read(){cin >> x >> y;}
    }P[MX];
    
    struct SEG{
    	VECTOR st ,d;
    	SEG(){st = d = VECTOR(0 ,0);}
    	SEG(VECTOR __st ,VECTOR __ed){
    		st = __st ,d = __ed - __st;
    	};
    	void turn(){
    		st = st + d;
    		d = VECTOR(0 ,0) - d;
    	}
    };
    
    int sgn(LL x){
    	if(!x) return 0;
    	return x > 0 ? 1 : -1;
    }
    
    bool PingXing(VECTOR A ,VECTOR B){
    	return A.x * B.y - A.y * B.x == 0;
    }
    
    bool online(SEG a ,VECTOR b){
    	// 询问点 b 是否在 a 上(含边缘)
    	bool xless = b.x < a.st.x && b.x < (a.st + a.d).x;
    	bool xmore = b.x > a.st.x && b.x > (a.st + a.d).x;
    	bool yless = b.y < a.st.y && b.y < (a.st + a.d).y;
    	bool ymore = b.y > a.st.y && b.y > (a.st + a.d).y;
    	return (xless + xmore + yless + ymore) == 0;
    }
    
    int ok(SEG a ,SEG b){
    	// 0 绝对不行
    	// 1 共点
    	// 2 绝对可以
    	LL test1 = sgn(a.d * (b.st - a.st)) * sgn(a.d * (b.st + b.d - a.st));
    	LL test2 = sgn(b.d * (a.st - b.st)) * sgn(b.d * (a.st + a.d - b.st));
    	if(test1 > 0 || test2 > 0){
    		// 连交点都没有
    		return 2;
    	}
    	if(PingXing(a.d ,b.d)){
    		// 有交点且平行就是共线
    		if(online(a ,b.st) || online(a ,b.st + b.d)
    		|| online(b ,a.st) || online(b ,a.st + a.d)){
    			// 二者有交
    			if(sgn(a.d.x) != sgn(b.d.x) || sgn(a.d.y) != sgn(b.d.y)){
    				b.turn();
    			}
    			if(a.st + a.d == b.st || b.st + b.d == a.st)
    				return 1;
    			return 0;
    		}
    		
    		return 2;
    	}
    	return (test1 <= 0 && test2 <= 0);
    }
    
    LL fad;
    int n;
    int check(int l ,int r){
    
    	if(l == 0 && r == 4){
    		puts("WTf");
    	}
    	SEG Main(P[l] ,P[r]);
    
    	LL S = fad ,s1 = 0 ,s2 = 0;
    	for(int i = l ; i <= r ; ++i){
    		if(i == r){
    			s1 += P[r] * P[l]; 
    		}
    		else{
    			s1 += P[i] * P[i + 1];
    		}
    	}
    	for(int i = r ; ; i = (i + 1) % n){
    		if(i == l){
    			s2 += P[l] * P[r];
    			break;
    		}
    		s2 += P[i] * P[(i + 1) % n];
    	}
    	if(abs(S) != abs(s1) + abs(s2)) return 0;
    
    	
    	for(int i = 0 ; i < n ; ++i){
    		SEG t(P[i] ,P[(i + 1) % n]);
    		int judge = ok(Main ,t);
    		if(i == r && ((i + 1) % n == l)) continue;
    		if(judge == 0) return 0;
    		if(judge == 1){
    			if(i == l || (i + 1) % n == l || i == r || (i + 1) % n == r){
    				continue;
    			}
    			return 0;
    		}
    	}
    	return 1;
    }
    
    LL dp[MX][MX];
    
    void test(){
    	int n; cin >> n;
    	while(n--){
    		int x ,y;
    		cin >> x >> y;
    		printf("(%d,%d)
    " ,x ,y);
    	}
    	SEG a(VECTOR(1 ,0) ,VECTOR(-1 ,0)) ,b(VECTOR(0 ,0) ,VECTOR(1 ,0));
    	cout << ok(a ,b) <<endl;
    	return ;
    }
    
    int main(){
    	// test();
    	cin >> n;
    	for(int i = 0 ; i < n ; ++i){
    		P[i].Read();
    	}
    	for(int i = 0 ; i < n ; ++i){
    		fad += P[i] * P[(i + 1) % n];
    	}
    	// fad 为正数说明是顺时针给出
    	for(int i = 1 ; i < n ; ++i){
    		dp[i - 1][i] = 1;
    	}
    	for(int len = 2 ; len <= n ; ++len){
    		for(int st = 0 ; st + len < n ; ++st){
    			int ed = st + len;
    			if(!check(st ,ed)){
    				printf("[%d ,%d] is bad!
    " ,st ,ed);
    
    				continue;
    			}
    			for(int k = st + 1 ; k < ed ; ++k){
    				dp[st][ed] = (dp[st][ed] + dp[st][k] * dp[k][ed]) % MOD;
    			}
    			printf("dp[%d][%d] = %lld
    " ,st ,ed ,dp[st][ed]);
    		}
    	}
    	cout << dp[0][n - 1] << endl;
    	return 0;
    }
    
  • 相关阅读:
    precmd:6: job table full or recursion limit exceeded
    Logs
    vue路由的使用(二)
    vue路由的使用(一)
    vue项目中正确引用jquery
    vue中使用Mint-UI移动端组件库
    HTML5表单、一些新增的输入类型以及为不支持新特性的浏览器提供解决方案
    CSS3过渡、变形、动画(二)
    CSS3过渡、变形、动画(一)
    CSS3之背景渐变
  • 原文地址:https://www.cnblogs.com/imakf/p/13828537.html
Copyright © 2011-2022 走看看