从零单排15

今天重新看刘汝佳的入门经典,果然有了不一样的感受

以前那本书看到第五章的重载运算符就很吃力了。。

现在经过一段时间的学习。。好多了。。

能感到动态规划那部分了。。。

然后就感觉吃力了。。

动态规划部分练习的还是太少,好多基本的模型还不知道。。。


刚刚趁学习遇到瓶颈做了三道计算几何,学习了

8. 计算几何
a) 判断点是否在线段上
b) 判断线段相交
c) 判断矩形是否包含点
d) 判断圆与矩形关系
e) 判断点是否在多边形内
f) 判断点到线段的最近点
g) 计算两个圆的公切线
h) 求矩形的并的面积
i) 求多边形面积
j) 求多边形重心
k) 求凸包


自己的代码没有对浮点数进行精度判断。。。

可见hdu的数据有多弱。。

题解:

hdu 1086:http://acm.hdu.edu.cn/showproblem.php?pid=1086

/*
计算几何-线段相交
套模版~
*/
#include<iostream>
using namespace std;
struct point 
{
	double x;
	double y;
};
point point1[105],point2[105];
struct line
{
	point start;
	point end;
};
double crossProduct(point p1,point p2,point p)//判断点是否在直线两边 
{
	return (p.x-p1.x)*(p2.y-p.y)-(p.y-p1.y)*(p2.x-p.x);
}
bool on_segment(point p1,point p2,point p)//判断点是否在线段上 
{
	double minx=min(p1.x,p2.x);
	double maxx=max(p1.x,p2.x);
	double miny=min(p1.y,p2.y);
	double maxy=max(p1.y,p1.y);
	if(minx<=p.x && maxx>=p.x && miny<=p.y && maxy>=p.y && crossProduct(p1,p2,p)==0)
	{
		return true;
	}
	else
	{
		return false;
	}
} 
bool segments_intersect(point p1,point p2,point p3,point p4)
{
	double d1=crossProduct(p1,p2,p3);
	double d2=crossProduct(p1,p2,p4);
	double d3=crossProduct(p3,p4,p1);
	double d4=crossProduct(p3,p4,p2);
	if(d1*d2<0 && d3*d4<0)
	{
		return true;
	}
	//d=0时为平行情况,此时需要考虑端点是否在线段上 
	else if(!d1 && on_segment(p3,p4,p1))
	{
		return true;
	}
	else if(!d2 && on_segment(p3,p4,p2))
	{
		return true;
	}
	else if(!d3 && on_segment(p1,p2,p3))
	{
		return true;
	}
	else if(!d4 && on_segment(p1,p2,p4))
	{
		return true;
	}
	else 
	{
		return false;
	}
}
int main()
{
	int n;
	while(cin>>n&&n!=0)
	{
		for(int i=1;i<=n;i++)
		{
			cin>>point1[i].x>>point1[i].y>>point2[i].x>>point2[i].y;
		}
		int cnt=0;
		for(int i=1;i<n;i++)
		{
			for(int j=i+1;j<=n;j++)
			{
				if(segments_intersect(point1[i],point2[i],point1[j],point2[j]))
				{
					cnt++;
				}
			}
		}
		cout<<cnt<<endl;
	}
	system("pause");
	return 0;
}
		

hdu 1147: http://acm.hdu.edu.cn/showproblem.php?pid=1147

/*
计算集合-线段相交
开一个flag[]数组标记该线段是否被覆盖 
依次遍历,若后续线段与之前线段相交,则将flag[之前线段]置0
最后统计flag为1的线段输出即可
*/
#include<iostream>
using namespace std;
struct point 
{
	double x;
	double y;
};
point point1[100005],point2[100005];
int ans[100005];
bool flag[100005];
double crossProduct(point p1,point p2,point p)//判断点是否在直线两边 
{
	return (p.x-p1.x)*(p2.y-p.y)-(p.y-p1.y)*(p2.x-p.x);
}
bool on_segment(point p1,point p2,point p)//判断点是否在线段上 
{
	double minx=min(p1.x,p2.x);
	double maxx=max(p1.x,p2.x);
	double miny=min(p1.y,p2.y);
	double maxy=max(p1.y,p1.y);
	if(minx<=p.x && maxx>=p.x && miny<=p.y && maxy>=p.y && crossProduct(p1,p2,p)==0)
	{
		return true;
	}
	else
	{
		return false;
	}
} 
bool segments_intersect(point p1,point p2,point p3,point p4)//判断线段相交 
{
	double d1=crossProduct(p1,p2,p3);
	double d2=crossProduct(p1,p2,p4);
	double d3=crossProduct(p3,p4,p1);
	double d4=crossProduct(p3,p4,p2);
	if(d1*d2<0 && d3*d4<0)
	{
		return true;
	}
	//d=0时为平行情况,此时需要考虑端点是否在线段上 
	else if(!d1 && on_segment(p3,p4,p1))
	{
		return true;
	}
	else if(!d2 && on_segment(p3,p4,p2))
	{
		return true;
	}
	else if(!d3 && on_segment(p1,p2,p3))
	{
		return true;
	}
	else if(!d4 && on_segment(p1,p2,p4))
	{
		return true;
	}
	else 
	{
		return false;
	}
}
int main()
{
	int n;
	while(cin>>n&&n!=0)
	{
		memset(flag,true,sizeof(flag));
		for(int i=1;i<=n;i++)
		{
			cin>>point1[i].x>>point1[i].y>>point2[i].x>>point2[i].y;
		}
		for(int i=1;i<n;i++)
		{
			for(int j=i+1;j<=n;j++)
			{
				if(segments_intersect(point1[i],point2[i],point1[j],point2[j]))
				{
					flag[i]=false;
					break;
				}
			}
		}
		int cnt=0;
		cout<<"Top sticks: ";
		for(int i=1;i<=n;i++)
		{
			if(flag[i])
			{
				ans[++cnt]=i;
			}
		}
		for(int i=1;i<cnt;i++)
		{
			cout<<ans[i]<<", ";
		}
		cout<<ans[cnt]<<"."<<endl;
	}
	system("pause");
	return 0;
}
			

hdu 1756: http://acm.hdu.edu.cn/showproblem.php?pid=1756

/*
计算几何-判断点是否在多边形内
垂直交叉点数判别法
从P向一“无穷远点”作射线,
如果P是多边形上边上,说明P在多边形内 
如果P在射线上,另作新射线,重新判断 
如果射线与多边形边相交,交点+1,最后判断总交点数奇偶性
*/
#include<iostream>
#include<cmath>
#define MAX 1000
using namespace std;
struct point 
{
	double x;
	double y;
};
point p[105],p1,p2;
double crossProduct(point p1,point p2,point p)//判断点是否在直线两边 
{
	return (p.x-p1.x)*(p2.y-p.y)-(p.y-p1.y)*(p2.x-p.x);
}
bool on_segment(point p1,point p2,point p)//判断点是否在线段上 
{
	double minx=min(p1.x,p2.x);
	double maxx=max(p1.x,p2.x);
	double miny=min(p1.y,p2.y);
	double maxy=max(p1.y,p1.y);
	if(minx<=p.x && maxx>=p.x && miny<=p.y && maxy>=p.y && crossProduct(p1,p2,p)==0)
	{
		return true;
	}
	else
	{
		return false;
	}
} 
bool segments_intersect(point p1,point p2,point p3,point p4)//判断线段相交 
{
	double d1=crossProduct(p1,p2,p3);
	double d2=crossProduct(p1,p2,p4);
	double d3=crossProduct(p3,p4,p1);
	double d4=crossProduct(p3,p4,p2);
	if(d1*d2<0 && d3*d4<0)
	{
		return true;
	}
	//d=0时为平行情况,此时需要考虑端点是否在线段上 
	else if(!d1 && on_segment(p3,p4,p1))
	{
		return true;
	}
	else if(!d2 && on_segment(p3,p4,p2))
	{
		return true;
	}
	else if(!d3 && on_segment(p1,p2,p3))
	{
		return true;
	}
	else if(!d4 && on_segment(p1,p2,p4))
	{
		return true;
	}
	else 
	{
		return false;
	}
}
bool inPoly(int n,point p1,point p[])//判断点是否在多边形内 
{
	int cnt;
	int i=0;
	p[0]=p[n]; 
	while(i<n)
	{
		p2.x=rand()+MAX; 
		p2.y=rand()+MAX;
		for(i=cnt=0;i<n;i++)
		{
			if(on_segment(p[i],p[i+1],p1))//点在边上 
			{
				return true;
			}
			else if(crossProduct(p1,p2,p[i])==0)//点在射线上,停止本循环,另取p2 
			{
				break;
			}
			else if(segments_intersect(p1,p2,p[i],p[i+1]))//射线与边相交,统计交点数 
			{
				cnt++;
			}
		}
	}
	if(cnt%2)
	{
		return true;
	}
	else
	{
		return false;
	}
}
int main()
{
	int n;
	while(cin>>n)
	{
		for(int i=1;i<=n;i++)
		{
			cin>>p[i].x>>p[i].y;
		}
		int m;
		cin>>m;
		while(m--)
		{
			cin>>p1.x>>p1.y;
			if(inPoly(n,p1,p))
			{
				cout<<"Yes"<<endl;
			}
			else
			{
				cout<<"No"<<endl;
			}
		}
	}
	system("pause");
	return 0;
}

晚上金山的复赛~

希望通过这一段时间的学习自己不要吃鸭蛋。。。

加了个油~


金山复赛第一场只做了一题。。。

第二场浮躁了。。。

一点也做不下去了。。。

今天把计算几何看了一点点。。

凸包什么的。。

模版


 题解:

hdu 1221:http://acm.hdu.edu.cn/showproblem.php?pid=1221

/*
分别判断矩形的四条边与圆的位置关系。。
没有思路。。
copy的discuss中的代码
学习。。
*/

/*
后来想了想。。
这题是基本题啊尼玛。。
矩形四边都是平行于坐标轴的。。。
。。。。。
*/
 
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
struct point
{
    double x;
    double y;
};
double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int major(point A,point B,point centre,double radius)
{
    double a,b,c;
    int flag;
    a=dis(centre,A),b=dis(centre,B);
    c=fabs(centre.y-A.y);
    if(centre.x<=A.x||centre.x>=B.x) //垂点在边线段外
    {
       if((a-radius)*(b-radius)<=0)
           flag=1;
       else
	   	   flag=0;
    }
    else //如果垂点在边线段上
     {
        if(c<=radius)
        {
            if(a>radius||b>radius)
                 flag=1;
            else 
				 flag=0;
        }
        else flag=0;
    }
    return flag;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        point centre,A,B,C,D;
        double radius;
        cin>>centre.x>>centre.y>>radius;
        cin>>A.x>>A.y>>C.x>>C.y;
        B.x=C.x,B.y=A.y,D.x=A.x,D.y=C.y;
        double a,b,c;
        int flag_1,flag_2,flag_3,flag_4;  //1为相交,0为相离
        flag_1=major(A,B,centre,radius);
        flag_2=major(B,C,centre,radius);
        flag_3=major(C,D,centre,radius);
        flag_4=major(D,A,centre,radius);
        if(flag_1||flag_2||flag_3||flag_4)
        	cout<<"YES"<<endl;
        else 
			cout<<"NO"<<endl;
    }
}

hdu 1348: http://acm.hdu.edu.cn/showproblem.php?pid=1348

/*
凸包模版。。
不解释了。。
尼玛想改成纯c++代码wa了一万遍了。。。。。。
回头再看。
我想知道为什么sort不行啊啊啊啊啊 
*/ 
/*
刚刚分别打印排序后结果发现
尼玛排序顺序竟然刚好相反。。
原来qsort 中如果返回a>b意思是顺序输出。。
而sort 如果返回a>b意思就是逆序啊。。。。
。。。
学习了!!!
*/
 
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream> 
#include <algorithm>
using namespace std;
const int N = 1005;
const double PI = 3.1415927;
struct point 
{
	double x;
    double y;
}p[N],stack[N];
 
double dis(point p1,point p2)
{
	return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
double crossProduct(point p1,point p2,point p)//判断点是否在直线两边 
{
	return (p.x-p1.x)*(p.y-p2.y)-(p.y-p1.y)*(p.x-p2.x);
}
 
 //以最左下的点为基准点,其他各点(逆时针方向)以极角从小到大的排序规则
bool cmp(const point &a, const point &b)
{
    double k=crossProduct(a,b,p[0]);//极角大小转化为求叉乘
    if (k<0 || !k && dis(p[0], a)>dis(p[0], b)) 
		return false;
    return true;
} 
double Graham(int n)
{
	double x = p[0].x;
    double y = p[0].y;
    int mi = 0;
    for(int i=1;i<n;++i)
	{//找到最左下的一个点
		if(p[i].x<x || (p[i].x==x&&p[i].y<y)) 
		{
			x=p[i].x;
            y=p[i].y;
            flag=i;
        }
    }
    swap(p[0],p[flag]);
    sort(p+1,p+n,cmp2);
    p[n]=p[0];
    stack[0]=p[0];
    stack[1]=p[1];
    stack[2]=p[2];
    int top=2;
    for(int i=3;i<=n;i++)
	{//加入一个点后,向右偏拐或共线,则上一个点不在凸包内,则--top,该过程直到不向右偏拐或没有三点共线的点 
		while(crossProduct(stack[top], p[i],stack[top-1])<=0 && top>=2) 
			--top;
        stack[++top]=p[i];//在当前情况下符合凸包的点,入栈
    }
    double len=0;
    for(int i=0;i<top;++i)
		len+=dis(stack[i],stack[i+1]);
    return len;
}
 
int main()
{
	int T;
    cin>>T;
	while(T--) 
	{
        int n,l;
        cin>>n>>l;
        for(int i=0;i<n;++i) 
		{
			cin>>p[i].x>>p[i].y;
		}
        double ans=Graham(n);
        ans+=PI*(l+l);
        printf("%.0lf\n",ans);
        if(T)
		{ 
			printf("\n");
        }
    }
    system("pause");
    return 0;
}

hdu 1392: http://acm.hdu.edu.cn/showproblem.php?pid=1392

/*
凸包模版。。
啊啊啊啊啊
好烦躁
*/
 

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>

using namespace std;

const int N = 105;
const double eps = 1e-8;

struct point {
    int x;
    int y;
}p[N], stack[N];

bool isZero(double x) {
    return (x > 0 ? x : -x) < eps;
}

double dis(point A, point B) {
    return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double crossProd(point A, point B, point C) {
    return (B.x-A.x)*(C.y-A.y) - (B.y-A.y)*(C.x-A.x);
}

//以最左下的点为基准点,其他各点(逆时针方向)以极角从小到大的排序规则
int cmp(const void *a, const void *b) {
    point *c = (point *)a;
    point *d = (point *)b;
    double k = crossProd(p[0], *c, *d);//极角大小转化为求叉乘
    if (k<eps || isZero(k) && dis(p[0], *c)>dis(p[0], *d)) return 1;
    return -1;
}

double Graham(int n) {
    int x = p[0].x;
    int y = p[0].y;
    int mi = 0;
    for (int i=1; i<n; ++i) {//找到最左下的一个点
        if (p[i].x<x || (p[i].x==x && p[i].y<y)) {
            x = p[i].x;
            y = p[i].y;
            mi = i;
        }
    }
    point tmp = p[mi];
    p[mi] = p[0];
    p[0] = tmp;
    qsort(p+1, n-1, sizeof(point), cmp);
    p[n] = p[0];
    stack[0] = p[0];
    stack[1] = p[1];
    stack[2] = p[2];
    int top = 2;
    for (int i=3; i<=n; ++i) {//加入一个点后,向右偏拐或共线,则上一个点不在凸包内,则--top,该过程直到不向右偏拐或没有三点共线的点 
        while (crossProd(stack[top-1], stack[top], p[i])<=eps && top>=2) --top;
        stack[++top] = p[i];//在当前情况下符合凸包的点,入栈
    }
    double len = 0;
    for (int i=0; i<top; ++i) len += dis(stack[i], stack[i+1]);
    return len;
}

int main() {
    int n;
    while (scanf("%d", &n), n) {
        for (int i=0; i<n; ++i) scanf ("%d%d", &p[i].x, &p[i].y);
        if (n == 1) printf ("0.00\n");
        else if (n == 2) printf ("%.2lf\n", dis(p[0], p[1]));
        else {
            double len = Graham(n);
            printf ("%.2lf\n", len);
        }
    }
    return 0;
}

难过的,都过去吧。

坚持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值