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;
    }
    
  • 相关阅读:
    C语言 realloc为什么要有返回值,realloc返回值具体解释/(解决随意长度字符串输入问题)。
    opencv中的vs框架中的Blob Tracking Tests的中文注释。
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
  • 原文地址:https://www.cnblogs.com/imakf/p/13828537.html
Copyright © 2011-2022 走看看