计算几何入门题之点,线,面,形基本关系以及点积叉积的理解

本人菜鸟一只,暑期做了一点计算几何的题目,现先将我之前转载的《计算几何题目推荐》的入门题的第一部分的解答与大家分享。

本篇所涉的题主要是与点,线,面,形基本关系以及点积叉积的理解相关的15道题,相对还是很基础的。但我这弱菜做的不太轻松。


POJ  2318 TOYS
题意:判断箱子每个块内有多少个玩具
分析:对于每个玩具的坐标,采用二分查找以确定玩具所在的块,其中玩具与分界(线段)的位置关系的判断可通过叉积来实现。
代码:

#include <stdio.h>
#include <string.h>
#define MAX 5010
struct Point
{
	int x,y;
};
struct Line
{
	Point p1,p2;
}line[MAX];

int m,n,x1,y1,x2,y2;
int a[MAX];

Line makeline(int x1,int y1,int x2,int y2)
{
	Line L;
	L.p1.x=x1;
	L.p1.y=y1;
	L.p2.x=x2;
	L.p2.y=y2;
	return L;
}

int direction(Point p1,Point p0,Point p2)
{
	return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}

bool isleft(Line l,Point p)
{
	if(direction(l.p1,l.p2,p)>0)return true;
	else return false;
}

int binary_search(Point p)//二分查找
{
	int low,high,mid;
	low=0;
	high=n;
	while(low<=high)
	{
		mid=(low+high)/2;
		if(isleft(line[mid],p))high=mid-1;
		else low=mid+1;
	}
	return high;
}

int main()
{
	int xx1,xx2,i,j;
	while(scanf("%d",&n)!=EOF&&n)
	{
		scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
		memset(a,0,sizeof(a));
		line[0]=makeline(x1,y1,x1,y2);
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&xx1,&xx2);
			line[i]=makeline(xx1,y1,xx2,y2);
		}
		line[n+1]=makeline(x2,y1,x2,y2);
		Point p;
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&p.x,&p.y);
			a[binary_search(p)]++;
		}
		for(i=0;i<=n;i++)
		{
			printf("%d: %d\n",i,a[i]);
		}
		printf("\n");
	}
	return 0;
}


POJ 2398 Toy Storage
题意:与上一题一样,只是输出不同
代码:

#include <stdio.h>
#include <vector>
#include<algorithm>
#include <string.h>
using namespace std;

#define MAX 5010
struct Point
{
	int x,y;
};
struct Line
{
	Point p1,p2;
}line[MAX];

struct Count
{
	int data,num;
}co;

int m,n,x1,y1,x2,y2;
int a[MAX],b[MAX];

bool Comp(Count c1,Count c2)
{
	return c1.num>c2.num;
}
bool Comp1(Line l1,Line l2)
{
	return l1.p1.x<l2.p1.x;
}
Line makeline(int x1,int y1,int x2,int y2)
{
	Line L;
	L.p1.x=x1;
	L.p1.y=y1;
	L.p2.x=x2;
	L.p2.y=y2;
	return L;
}

int direction(Point p1,Point p0,Point p2)
{
	return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}

bool isleft(Line l,Point p)
{
	if(direction(l.p1,l.p2,p)>0)return true;
	else return false;
}

int binary_search(Point p)//二分查找
{
	int low,high,mid;
	low=0;
	high=n;
	while(low<=high)
	{
		mid=(low+high)/2;
		if(isleft(line[mid],p))high=mid-1;
		else low=mid+1;
	}
	return high;
}

int main()
{
	int xx1,xx2,i;
	while(scanf("%d",&n)!=EOF&&n)
	{
		scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		line[0]=makeline(x1,y1,x1,y2);
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&xx1,&xx2);
			line[i]=makeline(xx1,y1,xx2,y2);
		}
		line[n+1]=makeline(x2,y1,x2,y2);
		sort(line,line+n+1,Comp1);
		Point p;
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&p.x,&p.y);
			a[binary_search(p)]++;
		}
		for(i=0;i<=n;i++)
			b[a[i]]++;
		printf("Box\n");
		for(i=1;i<=m;i++)
			if(b[i])
				printf("%d: %d\n",i,b[i]);
	}
	return 0;
}

POJ 3304 Segment
题意:判断是否存在一条直线,使得n条线段在该直线上的投影存在公共部分。
分析:若存在这样一条直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条线和所有线段相交;
若存在一条直线与所有线段相机相交,将该线旋转,平移,直到不能再动为止,此时该直线必定经过这些线段的某两个端点;
所以枚举任意两个端点即可,注意还要判重。(此思路是借鉴的别人的)
代码:

#include <stdio.h>
#include<cmath> 
const double ESP=1e-8;
const int MAXN=210;
struct Point
{
	double x,y;
}point[MAXN];

int dblcmp(double d)
{  
	if(fabs(d) <ESP)return 0;  
	else return d > 0 ? 1 : -1;  
}  
bool isEqual(double &a,double &b)
{
	return fabs(a-b)<ESP;
}
double multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
bool linecross(Point a,Point b,Point c,Point d)//过a,b的直线
{
	return dblcmp(multi(a,c,b))*dblcmp(multi(a,d,b))<=0;
}
int main()
{
	bool isfind;
	int T,n;
	scanf("%d",&T);
	while(T--)
	{
		isfind=false;
		scanf("%d",&n);
		for(int i=1;i<=2*n;i+=2)
			scanf("%lf%lf%lf%lf",&point[i].x,&point[i].y,&point[i+1].x,&point[i+1].y);
		for(int i=1;i<=2*n&&!isfind;i++)
			for(int j=i+1;j<=2*n;j++)
			{
				if(isEqual(point[i].x,point[j].x)&&isEqual(point[i].y,point[j].y))
					continue;//判重
				int k;
				for(k=1;k<2*n;k+=2)
				{
					if(!linecross(point[i],point[j],point[k],point[k+1]))
						break;
				}
				if(k>=2*n){isfind=true;break;}
			}
		if(isfind)printf("Yes!\n");
		else printf("No!\n");
	}
	return 0;
}

POJ 1269 Intersecting Lines
题意:直线相交判断(不相交、共线、相交),相交求交点
分析:没啥好分析的,略啦
代码:

#include <stdio.h>
#include <cmath>
const double ESP=1e-8;
#define isequal(x,y)(fabs(x-y)<ESP)

int dblcmp(double d)
{
	if(fabs(d)<ESP)
		return 0;
	return (d>0)?1:-1;
}

struct Point
{
	double x,y;
}p[5];

struct Line
{
	double a,b,c;
}line[2];

Line lineFromSegment(Point p1, Point p2)
{
	//线段所在直线,返回直线方程的三个系数 
	Line tmp;
	tmp.a = p2.y - p1.y;
	tmp.b = p1.x - p2.x;
	tmp.c = p2.x * p1.y - p1.x * p2.y;
	return tmp;
}

Point LineInter(Line l1, Line l2)
{
	//求两直线得交点坐标
	Point tmp; 
	if(fabs(l1.b) < ESP){ 
		tmp.x = -l1.c / l1.a;  
		tmp.y = (-l2.c - l2.a * tmp.x) / l2.b;
	}       
	else{
		tmp.x = (l1.c * l2.b - l1.b * l2.c) / (l1.b * l2.a - l2.b * l1.a);
		tmp.y = (-l1.c - l1.a * tmp.x) / l1.b;
	}
	return tmp;
}

double multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

int main()
{
	int T;
	scanf("%d",&T);
	for(int i=0;i<T;i++)
	{
		scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&p[0].x,&p[0].y,&p[1].x,&p[1].y,&p[2].x,&p[2].y,&p[3].x,&p[3].y);
		if(i==0)printf("INTERSECTING LINES OUTPUT\n");
		line[0]=lineFromSegment(p[0],p[1]);
		line[1]=lineFromSegment(p[2],p[3]);
		if(isequal(line[0].a*line[1].b,line[0].b*line[1].a))//isequal(line[0].a/line[0].b,line[1].a/line[1].b)是wrong answer,因为浮点除法有误差
		{
			if(!dblcmp(multi(p[0],p[1],p[2]))&&!dblcmp(multi(p[0],p[1],p[3])))//四点共线
				printf("LINE\n");
			else printf("NONE\n");
		}
		else
		{
			p[4]=LineInter(line[0],line[1]);
			printf("POINT %.2lf %.2lf\n",p[4].x,p[4].y);
		}
	}
	printf("END OF OUTPUT\n");
	return 0;
}

POJ 1556 The Doors
题意:求从(0,5)到(10,5)的最短距离,之间有墙和门。
分析:黑书上的一道习题,个人觉得此题主要是Dijkstra算法的应用,其次是线段相交的判断。
代码:

#include <stdio.h>
#include <math.h>
#include <vector>
using namespace std;
struct Point
{
	double x,y;
};
struct Seg
{
	Point a,b;
}seg[60];
vector<double>data[21];

double min(double x,double y)
{return x<y?x:y;} 
double max(double x,double y)
{return x>y?x:y;}

double multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

bool isIntersected(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)
{
	Point s1,e1,s2,e2;
	s1.x=x1;s1.y=y1;
	e1.x=x2;e1.y=y2;
	s2.x=x3;s2.y=y3;
	e2.x=x4;e2.y=y4;
	if(
		(max(s1.x, e1.x) >= min(s2.x, e2.x)) &&
		(max(s2.x, e2.x) >= min(s1.x, e1.x)) &&
		(max(s1.y, e1.y) >= min(s2.y, e2.y)) &&
		(max(s2.y, e2.y) >= min(s1.y, e1.y)) &&
		(multi(s2, e1, s1) * multi(e1, e2, s1) >0) &&
		(multi(s1, e2, s2) * multi(e2, e1, s2) >0)
		)  return true;
	return false;    
}

double distance(double ax,double ay,double bx,double by){  
	return sqrt((ax-bx)*(ax-bx)+(ay-by)*(ay-by));  
}

int fun(int x)//计算第x个墙的第一条线段的编号
{
	if(x==0)return 0;
	return (x-1)*3;
}
int main()
{
	int n;
	double dist[21][4];
	while(~scanf("%d",&n)&&n!=-1)
	{
		for(int i=0;i<21;i++)data[i].clear();
		data[0].push_back(0);
		data[0].push_back(5.0);
		int num_seg=0;
		for(int i=1;i<=n;i++)
		{
			double hh;
			for(int j=0;j<5;j++)
			{
				scanf("%lf",&hh);
				data[i].push_back(hh);
			}
			seg[num_seg].a.x=seg[num_seg].b.x=data[i][0];
			seg[num_seg].a.y=0;seg[num_seg].b.y=data[i][1];
			seg[num_seg+1].a.x=seg[num_seg+1].b.x=data[i][0];
			seg[num_seg+1].a.y=data[i][2];seg[num_seg+1].b.y=data[i][3];
			seg[num_seg+2].a.x=seg[num_seg+2].b.x=data[i][0];
			seg[num_seg+2].a.y=data[i][4];seg[num_seg+2].b.y=10.0;
			num_seg+=3;
		}
		data[n+1].push_back(10.0);data[n+1].push_back(5.0);
		for(int i=0;i<=n+1;i++)
			for(int j=0;j<4;j++)
				dist[i][j]=1000;
		dist[0][0]=0;
		for(int i=1;i<=n+1;i++)
			for(int j=1;j<data[i].size();j++)
			{
				for(int p=0;p<i;p++)
					for(int q=1;q<data[p].size();q++)
					{
						int k;
						for(k=fun(p);k<fun(i);k++)//亦可以 (k=0;k<num_seg;k++);当数据量很大时,前者效率高一点,但此题因数据少无所谓
						{
							if(isIntersected(data[i][0],data[i][j],data[p][0],data[p][q],seg[k].a.x,seg[k].a.y,seg[k].b.x,seg[k].b.y))
								break;
						}
						if(k==fun(i))
							dist[i][j-1]=min(dist[i][j-1],dist[p][q-1]+distance(data[i][0],data[i][j],data[p][0],data[p][q]));
					}
			}
		printf("%.2lf\n",dist[n+1][0]);
	}
	return 0;
}

POJ 2653 Pick-up sticks
题意:按顺序放置一定数量的枝条(线段),找到所有的不被压的枝条。
分析:针对每一个枝条,遍历在其后放的枝条,判断是否相交,若都不相交,则是符合条件的。
代码:

#include <stdio.h>
#include <string.h>
const int MAXN=100005;

struct Point
{
	double x,y;
};
struct Seg
{
	Point a,b;
}seg[MAXN];

double min(double x,double y)
{return x<y?x:y;} 
double max(double x,double y)
{return x>y?x:y;}

double multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

bool isIntersected(Point s1, Point e1, Point s2, Point e2)
{
	if(
		(max(s1.x, e1.x) >= min(s2.x, e2.x)) &&
		(max(s2.x, e2.x) >= min(s1.x, e1.x)) &&
		(max(s1.y, e1.y) >= min(s2.y, e2.y)) &&
		(max(s2.y, e2.y) >= min(s1.y, e1.y)) &&
		(multi(s2, e1, s1) * multi(e1, e2, s1) >= 0) &&
		(multi(s1, e2, s2) * multi(e2, e1, s2) >= 0)
		)  return true;
	return false;    
}

int mark[MAXN];
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		if(n==0)break;
		memset(mark,0,sizeof(mark));
		for(int i=1;i<=n;i++)
			scanf("%lf%lf%lf%lf",&seg[i].a.x,&seg[i].a.y,&seg[i].b.x,&seg[i].b.y);
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++)
			{
				if(isIntersected(seg[i].a,seg[i].b,seg[j].a,seg[j].b))
				{mark[i]=1;break;}
			}
		printf("Top sticks: ");   
		int k;
		for(k=1;k<=n;k++)
			if(!mark[k]){printf("%d",k);break;}
		for(int i=k+1;i<=n;i++)
			if(!mark[i])printf(", %d",i);
		printf(".\n");
	}
	return 0;
}

POJ 1066 Treasure Hunt
题意:在一个矩形区域内,有n条线段,线段的端点是在矩形边上的有一个特殊点end,问从这个点到矩形边的最少经过的线段(实际穿过线段时只能穿过中点)
分析:首先要要理解穿过最少门的意思,其实只要枚举end与矩形边上每小段的中点mid连线与几条线段相交就OK了。
代码:

#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;

struct Point
{
	double x,y;
}p,q[4];

struct Seg
{
	Point a,b;
}seg[31];
vector<Point>v[4];

bool Comp1(Point a,Point b)
{
	return a.x<b.x;
}
bool Comp2(Point a,Point b)
{
	return a.y<b.y;
}
bool Comp3(Point a,Point b)
{
	return a.x>b.x;
}
bool Comp4(Point a,Point b)
{
	return a.y>b.y;
}
void devide(Point po)
{
	if(po.y==0)v[0].push_back(po);
	else if(po.x==100.0)v[1].push_back(po);
	else if(po.y==100.0)v[2].push_back(po);
	else v[3].push_back(po);
}

Point getmid(Point p1,Point p2)
{
	Point temp;
	temp.x=(p1.x+p2.x)/2.0;
	temp.y=(p1.y+p2.y)/2.0;
	return temp;
}

double min(double x,double y)
{return x<y?x:y;} 
double max(double x,double y)
{return x>y?x:y;}

double multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

bool isIntersected(Point s1, Point e1, Point s2, Point e2)
{
	if(
		(max(s1.x, e1.x) >= min(s2.x, e2.x)) &&
		(max(s2.x, e2.x) >= min(s1.x, e1.x)) &&
		(max(s1.y, e1.y) >= min(s2.y, e2.y)) &&
		(max(s2.y, e2.y) >= min(s1.y, e1.y)) &&
		(multi(s2, e1, s1) * multi(e1, e2, s1) >= 0) &&
		(multi(s1, e2, s2) * multi(e2, e1, s2) >= 0)
		)  return true;

	return false;    
}

int main()
{
	int n;
	Point end;
	scanf("%d",&n);
	q[0].x=0;q[0].y=0;
	q[1].x=100.0;q[1].y=0;
	q[2].x=100.0;q[2].y=100.0;
	q[3].x=0;q[3].y=100.0;
	for(int i=0;i<4;i++)
		v[i].push_back(q[i]);
	for(int i=0;i<n;i++)
	{
		scanf("%lf%lf",&p.x,&p.y);
		devide(p);
		seg[i].a=p;
		scanf("%lf%lf",&p.x,&p.y);
		devide(p);
		seg[i].b=p;
	}
	scanf("%lf%lf",&end.x,&end.y);
	for(int i=0;i<3;i++)
		v[i].push_back(q[i+1]);
	v[3].push_back(q[0]);
	sort(v[0].begin(),v[0].end(),Comp1);
	sort(v[1].begin(),v[1].end(),Comp2);
	sort(v[2].begin(),v[2].end(),Comp3);
	sort(v[3].begin(),v[3].end(),Comp4);
	Point mid;
	Seg s;
	int big,now;
	big=30;
	for(int i=0;i<4;i++)
	{
		for(int j=0;j<v[i].size()-1;j++)
		{
			now=0;
			mid=getmid(v[i][j],v[i][j+1]);
			s.a=mid;
			s.b=end;
			for(int k=0;k<n;k++)
			{
				if(isIntersected(mid,end,seg[k].a,seg[k].b))now++;
			}
			if(now<big)big=now;
		}
	}
	printf("Number of doors = %d\n",big+1);
	return 0;
}

POJ 1410 Intersection

题意:判断给定线段是否与矩形相交

分析:很简单的题,将线段与矩形的四条边一次比较即可。此题还需注意的有:(1)线段在矩形内也算相交,不然过不了;(2)给出的左上顶点和右下顶点不保证x1<x2,y1>y2;即需要自己判断

代码:

#include <stdio.h>

struct Point
{
	int x,y;
};

struct Seg
{
	Point a,b;
}seg[5];
int xleft,xright,ybottom,ytop;

Seg makeseg(int x1,int y1,int x2,int y2)
{
	Seg temp;
	temp.a.x=x1;
	temp.a.y=y1;
	temp.b.x=x2;
	temp.b.y=y2;
	return temp;
}

int min(int x,int y)
{return x<y?x:y;} 
int max(int x,int y)
{return x>y?x:y;}

double multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

bool isIntersected(Point s1, Point e1, Point s2, Point e2)
{
	if(
		(max(s1.x, e1.x) >= min(s2.x, e2.x)) &&
		(max(s2.x, e2.x) >= min(s1.x, e1.x)) &&
		(max(s1.y, e1.y) >= min(s2.y, e2.y)) &&
		(max(s2.y, e2.y) >= min(s1.y, e1.y)) &&
		(multi(s2, e1, s1) * multi(e1, e2, s1) >= 0) &&
		(multi(s1, e2, s2) * multi(e2, e1, s2) >= 0)
		)  return true;

	return false;    
}

bool inrectangle()
{
	if((max(seg[0].a.x,seg[0].b.x)<xright)&&
		(min(seg[0].a.x,seg[0].b.x)>xleft)&&
		(max(seg[0].a.y,seg[0].b.y)<ytop)&&
		(min(seg[0].a.y,seg[0].b.y)>ybottom))
		return true;
	return false;
}

int main()
{
	int n;
	int flag;
	scanf("%d",&n);
	while(n--)
	{
		flag=0;
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&seg[0].a.x,&seg[0].a.y,&seg[0].b.x,&seg[0].b.y);
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		xleft=min(x1,x2);
		xright=max(x1,x2);
		ytop=max(y1,y2);
		ybottom=min(y1,y2);
		//scanf("%d%d%d%d",&xleft,&ytop,&xright,&ybottom);
		seg[1]=makeseg(xleft,ybottom,xright,ybottom);
		seg[2]=makeseg(xright,ybottom,xright,ytop);
		seg[3]=makeseg(xleft,ytop,xright,ytop);
		seg[4]=makeseg(xleft,ybottom,xleft,ytop);
		if(inrectangle())flag=1;
		else
			for(int i=1;i<=4;i++)
			{
				if(isIntersected(seg[0].a,seg[0].b,seg[i].a,seg[i].b))
				{
					flag=1;
					break;
				}
			}
		if(flag)printf("T\n");
		else printf("F\n");
	}
	return 0;
}

POJ 1696 Space Ant

题意:一只蚂蚁,只会向左转,现在给出平面上很多个点,求解一种走法,能使得蚂蚁能经过的点最多,每个顶点该蚂蚁只能经过一次,且所行走的路线不能发生交叉。

分析:这题考查了凸包的性质,是Graham算法的应用。先选取最左下方的(下的优先级比左高)点,然后对剩下的点进行极角排序,选取最小的;重复操作,直至所有的点都被选中输出。其实无论输入什么样的点集,一定可以走完全部n个点的,这是凸包的性质决定。

代码:

#include <stdio.h>
#include<math.h>
#include <algorithm>
using namespace std;
struct Point
{
	int x,y,code;
};
Point p[51];
int count1;
int multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

double Distance(Point a,Point b){  //若函数名为distance,则跟std::distance冲突了
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)*1.0);  
}

bool Comp(Point a,Point b)
{
	int temp=multi(a,b,p[count1]);
	if(temp>0)return true;
	else if(temp==0&&Distance(a,p[count1])<Distance(b,p[count1]))
		return true;
	return false;
}

void swap(Point &a,Point &b)
{
	Point p1;
	p1=a;
	a=b;
	b=p1;
}

int main()
{
	int T;
	int n;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d%d",&p[i].code,&p[i].x,&p[i].y);
			if(p[i].y<p[1].y)swap(p[1],p[i]);
		}
		printf("%d %d",n,p[1].code);
		count1=1;
		while(count1<n)
		{
			sort(p+count1+1,p+n+1,Comp);
			printf(" %d",p[count1+1].code);
			count1++;
		}
		printf("\n");
	}
	return 0;
}

POJ 3347 Kadj Squares

题意:给n个正方形,要求45°角放置,最左边的正方形紧贴Y轴,所有的正方形的下面的端点都在X轴上。然后按照正方形不能交错但要尽可能的挨着的原则摆放,找到所有从上往下看能看到的正方形。

分析:感觉这题比较复杂,是看了discuss和解题报告才AC了的。这题是转化为线段来做,直接将每个正方形的与X轴平行的角对角线作为处理对象。先确定线段的左右顶点,然后暴力扫描判断线段是否被遮挡。另外,因为该线段长度是根号二的倍数,为了避免小数的运算,可将线段长度扩大2倍,将边长乘以2即可。

代码:

#include <stdio.h>
#include <cmath>

struct Seg
{
	int left,right,len;
}seg[51];

int max(int x,int y)
{
	if(x>y)return x;
	return y;
}

int main()
{
	int n;
	while(~scanf("%d",&n)&&n)
	{
		for(int i=0;i<n;i++)
		{
			scanf("%d",&seg[i].len);
			seg[i].left=0;
			for(int j=0;j<i;j++)
				seg[i].left=max(seg[i].left,seg[j].right-abs(seg[i].len-seg[j].len));
			seg[i].right=seg[i].left+(seg[i].len<<1);
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<i;j++)
			{
				if(seg[i].left<seg[i].right)
				{
					if(seg[i].left<seg[j].right)
					{
						if(seg[i].len<seg[j].len)seg[i].left=seg[j].right;
						else seg[j].right=seg[i].left;
					}
				}
				else break;
			}
		}
		int k;
		for(k=0;k<n;k++)
			if(seg[k].left < seg[k].right)  
			{ printf("%d",k+1);break;}
		for(int i = k+1; i < n; i++)  
		{  
			if(seg[i].left < seg[i].right)  
				printf(" %d",i+1);
		}  
		printf("\n");  
	} 
	return 0;
}

POJ 2826 An Easy Problem?!

题意:由两块木板组成的装置,求能盛放的水量。

分析:显然没想象的那么简单,需要考虑的有很多。注意点:两条线不相交,左边或右边的口被遮住,交点是某条线的那个纵坐标较高的那点某条线段水平放置。

代码:

#include <stdio.h>
#include <cmath>
#define ESP 1e-8 
struct Point
{
	double x,y;
}p[4];

struct Line
{
	double a,b,c;
}line[2],l;


Point getp(Point a,Point b,double y0)
{
	if(y0==b.y)return b;
	double x0=fabs(a.x-(y0-a.y)*fabs((a.x-b.x))/(b.y-a.y));
	Point temp;
	temp.x=x0;
	temp.y=y0;
	return temp;
}

double min(double x,double y)
{return x<y?x:y;} 
double max(double x,double y)
{return x>y?x:y;}

double multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

bool isIntersected(Point s1, Point e1, Point s2, Point e2)
{
	//判断线段[s1, e1]和[s2, e2]是否相交
	//1.快速排斥试验判断以两条线段为对角线的两个矩形是否相交 
	//2.跨立试验
	if(
		(max(s1.x, e1.x) >= min(s2.x, e2.x)) &&
		(max(s2.x, e2.x) >= min(s1.x, e1.x)) &&
		(max(s1.y, e1.y) >= min(s2.y, e2.y)) &&
		(max(s2.y, e2.y) >= min(s1.y, e1.y)) &&
		(multi(s2, e1, s1) * multi(e1, e2, s1) >= 0) &&
		(multi(s1, e2, s2) * multi(e2, e1, s2) >= 0)
		)  return true;
	return false;    
}

Line lineFromSegment(Point p1, Point p2)
{
	//线段所在直线,返回直线方程的三个系数 
	Line tmp;
	tmp.a = p2.y - p1.y;
	tmp.b = p1.x - p2.x;
	tmp.c = p2.x * p1.y - p1.x * p2.y;
	return tmp;
}

Point LineInter(Line l1, Line l2)
{
	//求两直线得交点坐标
	Point tmp; 
	if(fabs(l1.b) < ESP){ 
		tmp.x = -l1.c / l1.a;  
		tmp.y = (-l2.c - l2.a * tmp.x) / l2.b;
	}       
	else{
		tmp.x = (l1.c * l2.b - l1.b * l2.c) / (l1.b * l2.a - l2.b * l1.a);
		tmp.y = (-l1.c - l1.a * tmp.x) / l1.b;
	}
	return tmp;
}

void swap(Point &a,Point &b)
{
	Point temp;
	temp=a;
	a=b;
	b=temp;
}


int main()
{
	int n;
	double s;
	scanf("%d",&n);

	int de=1;
	while(n--)
	{
		for(int i=0;i<4;i++)
			scanf("%lf%lf",&p[i].x,&p[i].y);
		//printf("Case %d:",de++);
		Point cross_point;
		if(!isIntersected(p[0],p[1],p[2],p[3]))
			printf("0.00\n");
		else//相交
		{
			line[0]=lineFromSegment(p[0],p[1]);
			line[1]=lineFromSegment(p[2],p[3]);
			cross_point=LineInter(line[0],line[1]);
			int num=0;//计算比交点高的点数
			Point cp[2];
			for(int i=0;i<4;i++)
				if(p[i].y>cross_point.y)
					cp[num++]=p[i];
			if(num<=1)printf("0.00\n");
			else
			{
				if(cp[0].y>cp[1].y)swap(cp[0],cp[1]);
				if((cp[0].x>cross_point.x&&cp[0].x<=cp[1].x&&multi(cp[1],cp[0],cross_point)<0)||(cp[0].x>=cp[1].x&&cp[0].x<cross_point.x&&multi(cp[1],cp[0],cross_point)>0))
					printf("0.00\n");
				else
				{
					Point p1,p2;
				    p1.x=cp[0].x+1;
					p1.y=cp[0].y;
					line[0]=lineFromSegment(p1,cp[0]);
					line[1]=lineFromSegment(cross_point,cp[1]);
					p2=LineInter(line[0],line[1]);
					s=fabs(multi(p2,cp[0],cross_point))/2.0;
					printf("%.2lf\n",s);
				}
			}
		}
	}
	return 0;
}



POJ 1039 Pipe

题意:有一宽度为1的折线管道,上面各顶点为(X0,Y0),(X1,Y1),……,(Xn,Yn),下面各顶点为(X0,Y0-1),(X1,Y1-1),……,(Xn,Yn-1),假设管壁都是不透明、不反射的,光线从左边入口处的(X0,Y0),(X0,Y0-1)之间射入,向四面八方直线传播,问光线最远能射到哪里(x坐标)或者能穿透整个管壁。

分析:本题上下顶点对于限制光线非常关键。解决方法:任取两个顶点,判断这两点所在直线是否能从入口射进到达该处,若能,则继续向后判断,看能否穿过其后的所有线段(Xi,Yi)(Xi,Yi-1),一旦与线段(Xk,Yk)(Xk,Yk-1)不相交,则交点必在前方,求交点。大概思路就这样,还算比较简洁。

代码:

#include <stdio.h>
#include<cmath> 
#define ESP 1e-8 
#define INF 99999
int dblcmp(double d)
{
	if(fabs(d)<ESP)
		return 0;
	return (d>0)?1:-1;
}

struct Point
{
	double x,y;
}p[42];

struct Line
{
	double a,b,c;
};

Line lineFromSegment(Point p1, Point p2)
{
	//线段所在直线,返回直线方程的三个系数 
	Line tmp;
	tmp.a = p2.y - p1.y;
	tmp.b = p1.x - p2.x;
	tmp.c = p2.x * p1.y - p1.x * p2.y;
	return tmp;
}

double cross(Point a,Point b,Point c)
{
	return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
//判断直线ab和线段cd是否相交,相交为true,不相交为false 
bool linecross(Point a,Point b,Point c,Point d)
{
	int d1,d2;
	d1=dblcmp(cross(a,c,b));
	d2=dblcmp(cross(a,d,b));
	if(d1*d2>0) return false;
	return true;
}

bool linecross1(Point a,Point b,Point c,Point d)
{
	int d1,d2;
	d1=dblcmp(cross(a,c,b));
	d2=dblcmp(cross(a,d,b));
	if(d1*d2>=0) return false;
	return true;
}
Point LineInter(Point a,Point b,Point c,Point d)
{
	//求两直线得交点坐标
	Line l1,l2;
	l1=lineFromSegment(a,b);
	l2=lineFromSegment(c,d);
	Point tmp;
	if(fabs(l1.b) < ESP){
		tmp.x = -l1.c / l1.a;  
		tmp.y = (-l2.c - l2.a * tmp.x) / l2.b;
	}       
	else{
		tmp.x = (l1.c * l2.b - l1.b * l2.c) / (l1.b * l2.a - l2.b * l1.a);
		tmp.y = (-l1.c - l1.a * tmp.x) / l1.b;
	}
	return tmp;
}

int main()
{
	int n;
	int flag;
	while(~scanf("%d",&n)&&n)
	{
		flag=0;
		for(int i=0,j=n;i<n;i++,j++)
		{
			scanf("%lf%lf",&p[i].x,&p[i].y);
			p[j].x=p[i].x;
			p[j].y=p[i].y-1;
		}
		double max=-1*INF ,now;
		for(int i=0;i<n;i++)
		{
			for(int j=n;j<2*n;j++)
			{
				if(i+n==j)continue;
				int k,rp=0,h;
				if(i>j-n)h=i;
				else h=j-n;
				for(k=0;k<h;k++)
					if(!linecross(p[i],p[j],p[k],p[k+n])){rp=1;break;}
				if(rp)continue;//该直线不可能从入口射进或射进但被挡住达不到i,j处
				for(k=h+1;k<n;k++)
				{
					if(!linecross(p[i],p[j],p[k],p[k+n]))
					{
						if(linecross1(p[i],p[j],p[k-1],p[k]))
						{
							now=LineInter(p[i],p[j],p[k-1],p[k]).x;
						}
						else now=LineInter(p[i],p[j],p[k+n-1],p[k+n]).x;
						if(now>max)max=now;
						break;
					}
				}
				if(k==n){flag=1;break;}
			}
			if(flag)break;
		}
		if(flag)printf("Through all the pipe.\n");
		else printf("%.2lf\n",max);
	}
	return 0;
}

POJ 3449 Geometric Shapes

题意:给一些几何图形,判断相交情况,按要求输出。

分析:题目不难,但很复杂,很烦。暴力枚举,只要注意输入输出就行。还有一个知识点,就是如何根据所给正方形(边不与轴平行)的两个对角线上的顶点,求另外两个点。

方法如下:

已知正方形的一对不相邻的顶点(x0,y0),(x2,y2),可以由方程组:

x1 + x3 = x0 + x2;

x1 - x3 = y2 - y0;

y1 + y3 = y0 + y2;

y3 - y1 = x2 - x0;

求得另一对不相邻的顶点(x1,y1),(x3,y3)。

代码:

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include<vector>
using namespace std;
struct Point
{
	double x,y;
};

struct Shape
{
	char label;
	int pn;
	Point p[20];
}shape[31];
vector<char>v[30];
Point input()
{
	Point tmp;
	char c;
	while((c=getchar())!=')')
	{
		if(c=='(')
			scanf("%lf",&tmp.x);
		else if(c==',')
			scanf("%lf",&tmp.y);
	}
	return tmp;
}

bool comp(Shape s1,Shape s2)
{
	return s1.label<s2.label;
}

double min(double x,double y)
{return x<y?x:y;} 
double max(double x,double y)
{return x>y?x:y;}

double multi(Point p1, Point p2, Point p0)
{
	return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

bool isintersected(Point s1, Point e1, Point s2,Point e2)
{
	if(
		(max(s1.x, e1.x) >= min(s2.x, e2.x)) &&
		(max(s2.x, e2.x) >= min(s1.x, e1.x)) &&
		(max(s1.y, e1.y) >= min(s2.y, e2.y)) &&
		(max(s2.y, e2.y) >= min(s1.y, e1.y)) &&
		(multi(s2, e1, s1) * multi(e1, e2, s1) >= 0) &&
		(multi(s1, e2, s2) * multi(e2, e1, s2) >= 0)
		)  return true;
	return false;    
}

bool isintersect(Shape s1,Shape s2)
{
	for(int i=0;i<s1.pn-1;i++)
	{
		int j;
		for(j=0;j<s2.pn-1;j++)
			if(isintersected(s1.p[i],s1.p[i+1],s2.p[j],s2.p[j+1]))
				return true;
		if(isintersected(s1.p[i],s1.p[i+1],s2.p[j],s2.p[0]))
			return true;
	}
	for(int i=0;i<s2.pn-1;i++)
		if(isintersected(s1.p[s1.pn-1],s1.p[0],s2.p[i],s2.p[i+1]))
			return true;
	if(isintersected(s1.p[s1.pn-1],s1.p[0],s2.p[s2.pn-1],s2.p[0]))
		return true;
	return false;
}
int main()
{
	char c;
	char name[20];
	int count=0;
	while(~scanf("%c",&c)&&c!='.')
	{
		if(c=='-')
		{
			sort(shape,shape+count,comp);
			for(int i=0;i<30;i++)
				v[i].clear();
			for(int i=0;i<count;i++)
			{
				for(int j=i+1;j<count;j++)
				{
					if(isintersect(shape[i],shape[j]))
					{
						v[i].push_back(shape[j].label);
						v[j].push_back(shape[i].label);
					}
				}
			}
			for(int i=0;i<count;i++)
			{
				printf("%c ",shape[i].label);
				if(v[i].size()==0)printf("has no intersections\n");
				else
				{
					printf("intersects with ");
					if(v[i].size()==1)printf("%c\n",v[i][0]);
					else if(v[i].size()==2)
						printf("%c and %c\n",v[i][0],v[i][1]);
					else
					{
						for(int j=0;j<v[i].size()-1;j++)
							printf("%c, ",v[i][j]);
						printf("and %c\n",v[i][v[i].size()-1]);
					}
				}
			}
			printf("\n");
			count=0;
		}
		else if(c>='A'&&c<='Z')
		{
			shape[count].label=c;
			scanf("%s",name);
			if(!strcmp(name,"square"))
			{
				shape[count].pn=4;
				Point temp0,temp2;
				temp0=input();
				temp2=input();
				shape[count].p[0]=temp0;
				shape[count].p[2]=temp2;
				shape[count].p[1].x=(temp0.x+temp2.x+temp2.y-temp0.y)/2.0;
				shape[count].p[1].y=(temp0.y+temp2.y-temp2.x+temp0.x)/2.0;
				shape[count].p[3].x=temp0.x+temp2.x-shape[count].p[1].x;
				shape[count].p[3].y=temp2.x-temp0.x+shape[count].p[1].y;
			}
			else if(!strcmp(name,"line"))
			{
				shape[count].pn=2;
				shape[count].p[0]=input();
				shape[count].p[1]=input();
			}
			else if(!strcmp(name,"rectangle"))
			{
				shape[count].pn=4;
				shape[count].p[0]=input();
				shape[count].p[1]=input();
				shape[count].p[2]=input();
				shape[count].p[3].x=shape[count].p[0].x+shape[count].p[2].x-shape[count].p[1].x;
				shape[count].p[3].y=shape[count].p[0].y+shape[count].p[2].y-shape[count].p[1].y;
			}
			else if(!strcmp(name,"triangle"))
			{
				shape[count].pn=3;
				shape[count].p[0]=input();
				shape[count].p[1]=input();
				shape[count].p[2]=input();
			}
			else// if(name=="polygon")
			{
				scanf("%d",&shape[count].pn);
				for(int i=0;i<shape[count].pn;i++)
					shape[count].p[i]=input();
			}
			count++;
		}
	}
	return 0;
}

POJ 1584 A Round Peg in a Ground Hole

题意:判断一个多边形是否为凸多边形,如果不是则输出”HOLE IS ILL-FORMED“,如果是则继续判断给定的一个圆是否在该凸多边形内,如果不在输出”PEG WILL NOT FIT“,否则输出”PEG WILL FIT“;

分析:判断是否为凸多边形,用向量叉积即可。判断圆是否在多边形内,先通过环顾法判断圆心是否在多边形内(环顾法黑书上有介绍),然后再判断是否圆心到各边的距离都大于半径。

代码:

#include <stdio.h>
#include <cmath>
const double ESP=1e-8;
const double pi=3.141592654;  
struct Point
{
	double x,y;
}p[100];
struct Line
{
	double a,b,c;
};
int dblcmp(double d)
{
	if(fabs(d)<ESP)
		return 0;
	return (d>0)?1:-1;
}

Line lineFromSegment(Point p1, Point p2)
{
	//线段所在直线,返回直线方程的三个系数 
	Line tmp;
	tmp.a = p2.y - p1.y;
	tmp.b = p1.x - p2.x;
	tmp.c = p2.x * p1.y - p1.x * p2.y;
	return tmp;
}
int n;
double cx,cy,cr;

double multi(Point a,Point b,Point c)//连续三点
{
	return (b.x-a.x)*(c.y-b.y)-(c.x-b.x)*(b.y-a.y);
}

double pointmulti(Point a,Point b,Point c)//点积ab*ac
{
	return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y);
}

bool isill_formed()//判断是否为凹的
{
	double dirction=multi(p[0],p[1],p[2]);
	for(int i=1;i<=n-3;i++)
		if(multi(p[i],p[i+1],p[i+2])*dirction<0)
			return true;
	if(multi(p[n-2],p[n-1],p[0])*dirction<0||
		multi(p[n-1],p[0],p[1])*dirction<0)
		return true;
	return false;
}
double dis(double cx,double cy,Point a,Point b)//圆心(cx,cy)到线段a,b的距离
{
	Line l=lineFromSegment(a,b);
	double dist;
	dist=abs(l.a*cx+l.b*cy+l.c)/sqrt(l.a*l.a+l.b*l.b);
	return dist;
}
double dis1(double cx,double cy,Point p)//圆心到顶点的距离
{
	return sqrt((p.x-cx)*(p.x-cx)+(p.y-cy)*(p.y-cy));
}
bool iscir_in_pol()
{
	double total=0;
	Point cp;
	cp.x=cx;cp.y=cy;
	for(int i=0;i<n-1;i++)//环顾法判断圆心是否在多边形内
		total+=acos(pointmulti(cp,p[i],p[i+1])/(dis1(cx,cy,p[i])*dis1(cx,cy,p[i+1])));
	total+=acos(pointmulti(cp,p[n-1],p[0])/(dis1(cx,cy,p[n-1])*dis1(cx,cy,p[0])));
	if(dblcmp(total-2*pi)!=0)return false;
	for(int i=0;i<n-1;i++)//圆心到各边的距离满足条件
	{
		if(dis(cx,cy,p[i],p[i+1])<cr)return false;
	}
	if(dis(cx,cy,p[0],p[n-1])<cr)return false;
	return true;
}

int main()
{
	while(~scanf("%d",&n)&&n>2)
	{
		scanf("%lf%lf%lf",&cr,&cx,&cy);
		for(int i=0;i<n;i++)
		{
			scanf("%lf%lf",&p[i].x,&p[i].y);
		}
		if(isill_formed())printf("HOLE IS ILL-FORMED\n");
		else
		{
			if(!iscir_in_pol())printf("PEG WILL NOT FIT\n");
			else printf("PEG WILL FIT\n");
		}
	}
	return 0;
}

POJ 2074 Line of Sight 

题意:给出House和Property Line的位置,还有若干个障碍物的位置,求出在Property Line上的最长的线段,满足在该线段上的所有的点都能看到完整的房子;若不存在这样的线段则输出“No View”。

分析:首先有个注意点说一下,障碍物可能不在house与Property Line之间,得对输入数据进行过滤。然后,针对每个障碍物,求其在Property Line上可遮挡住的地方。实现方法就是求house.right与line.left(障碍物的左顶点)的所在直线与pl的交点;求house.left与line.right的所在直线与pl的交点。这样就可求得遮挡的地方(其实就是线段);再然后,求所有遮挡住的地方的交集;最后扫描一遍即可求得最大长度。

代码:

#include<stdio.h>
#include <vector>
#include<cmath> 
#include <algorithm>
#define ESP 1e-8 
using namespace std;

int dblcmp(double d)
{
	if(fabs(d)<ESP)
		return 0;
	return (d>0)?1:-1;
}
struct Point
{
	double x,y;
};

struct Object
{
	Point left,right;
}house,pl,line;

struct Line
{
	double a,b,c;
};
struct Seg
{
	double xl,xr;
}seg;
Line lineFromSegment(Point p1, Point p2)
{
	//线段所在直线,返回直线方程的三个系数 
	Line tmp;
	tmp.a = p2.y - p1.y;
	tmp.b = p1.x - p2.x;
	tmp.c = p2.x * p1.y - p1.x * p2.y;
	return tmp;
}

double LineInter(Point a,Point b,Point c,Point d)
{
	//求两直线得交点坐标
	Line l1=lineFromSegment(a,b);
	Line l2=lineFromSegment(c,d);
	Point tmp; 
	if(fabs(l1.b) < ESP){ 
		tmp.x = -l1.c / l1.a;  
		//tmp.y = (-l2.c - l2.a * tmp.x) / l2.b;
	}       
	else{
		tmp.x = (l1.c * l2.b - l1.b * l2.c) / (l1.b * l2.a - l2.b * l1.a);
		//tmp.y = (-l1.c - l1.a * tmp.x) / l1.b;
	}
	return tmp.x;
}
//计算a,b,c三点的叉积,判断a,b,c三点的位置关系 
double cross(Point a,Point b,Point c)
{
	return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
//判断直线ab和线段cd是否相交,相交为true,不相交为false 
bool linecross(Point a,Point b,Point c,Point d)
{
	int d1,d2;
	d1=dblcmp(cross(a,c,b));
	d2=dblcmp(cross(a,d,b));
	if(d1*d2>0) return false;
	return true;
}
vector<Seg>v;
bool comp(Seg s1,Seg s2)
{
	return s1.xl<s2.xl;
}

bool isbetween(double yy)
{
	if((yy>house.left.y&&yy<pl.left.y)||(yy<house.left.y&&yy>pl.left.y))
		return true;
	return false;
}

int main()
{
	double x1,x2,y;
	int n;
	while(~scanf("%lf%lf%lf",&x1,&x2,&y))
	{
		if(x1==0&&x2==0&&y==0)break;
		house.left.x=x1;
		house.right.x=x2;
		house.right.y=house.left.y=y;
		scanf("%lf%lf%lf",&pl.left.x,&pl.right.x,&pl.left.y);
		pl.right.y=pl.left.y;
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%lf%lf%lf",&line.left.x,&line.right.x,&line.left.y);
			line.right.y=line.left.y;
			if(!isbetween(line.right.y))//预处理
			{i--;n--;}
			else
			{
				seg.xl=LineInter(house.right,line.left,pl.left,pl.right);
				if(seg.xl>=pl.right.x){i--;n--;continue;}
				else if(seg.xl<pl.left.x)
					seg.xl=pl.left.x;
				seg.xr=LineInter(house.left,line.right,pl.left,pl.right);
				if(seg.xr<=pl.left.x){i--;n--;continue;}
				else if(seg.xr>pl.right.x)
					seg.xr=pl.right.x;
				v.push_back(seg);
			}
		}
		//求集合
		double max=0.0;
		if(v.size()>0)
		{
			double length=0,sx,ex;
			sx=ex=pl.left.x;
			sort(v.begin(),v.end(),comp);
			for(int i=0;i<v.size();i++)
			{
				if(v[i].xl>ex)
				{
					length=v[i].xl-ex;
					if(length>max)max=length;
					sx=v[i].xl;
					ex=v[i].xr;
				}
				else if(v[i].xr>ex)
					ex=v[i].xr;
			}
			length=pl.right.x-ex;
			if(length>max)max=length;
		}
		else max=pl.right.x-pl.left.x;
		if(max>0)printf("%.2lf\n",max);
		else printf("No View\n");
		v.clear();
	}
	return 0;
}

完毕。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值