BZOJ1137: [POI2009]Wsp 島嶼

題目大意:平面上給出N個島嶼形成一個凸多邊形,兩兩島嶼之間有邊相連,道路相交處視爲分岔路口。現在有M條道路毀壞了,但是道路相交處仍可正常通行,求從1到N的最短距離

挺厲害的題...
首先由於是一個凸多邊形,所以最優方案是沿着"完好無損的那些道路的半平面交"來走
(畫個圖感受一下還是挺明顯的)
但是直接做是不行的,因爲有O(N^2)個限制
所以我們考慮去掉一些無用的半平面...
還是由於這是一個凸多邊形,所以對於一個點i,只有和他相連的標號最大的那個點與他形成的半平面是有用的,所以我們對於每個點只保留一個(i,last[i])的半平面就好了
這樣半平面個數就降爲了O(N)的

直接上半平面交就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#define N 100010
using namespace std;
vector<int>V[N];
int last[N];
struct node{double x,y;};
struct line{node a,b;double ang;};
node operator +(const node &x,const node &y){return (node){x.x+y.x,x.y+y.y};}
node operator -(const node &x,const node &y){return (node){x.x-y.x,x.y-y.y};}
node operator *(const node &x,const double &y){return (node){x.x*y,x.y*y};}
double xj(node x,node y){return x.x*y.y-x.y*y.x;}
bool cmp(line x,line y)
{
	if(x.ang!=y.ang) return x.ang<y.ang;
	return xj(y.b-x.a,y.a-x.a)>0;
}
double sqr(double x){return x*x;}
double dis(node x,node y){return sqrt(sqr(y.x-x.x)+sqr(y.y-x.y));}
bool left(node x,line y){return xj(y.a-x,y.b-x)>=0;}
void print(node x){cout<<x.x<<' '<<x.y<<' ';}
void print(line x){print(x.a);cout<<'*';print(x.b);cout<<endl;}
node jiao(line x,line y)
{
	double b=xj(x.b-x.a,y.a-x.a)/xj(y.b-y.a,x.b-x.a);
	return y.a+(y.b-y.a)*b;
}
node a[N];
line L[N];
line q[N];
int h,t;
node p[N];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	int i,j,x,y;
	for(i=1;i<=n;i++)
	scanf("%lf%lf",&a[i].x,&a[i].y);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		V[x].push_back(y);V[y].push_back(x);
	}
	for(i=1;i<=n;i++)
	{
		sort(V[i].begin(),V[i].end());
		int s=V[i].size();
		for(j=s-1;j>=0;j--)
		{
			if(V[i][j]!=n-s+j+1)
			{
				last[i]=n-s+j+1;
				break;
			}
		}
		if(j==-1) last[i]=n-s;
	}
	if(last[1]==n) {printf("%.9lf",dis(a[1],a[n]));return 0;}
	int cnt=0;
	for(i=1;i<=n;i++)
	if(last[i]>i)
	{
		cnt++;
		L[cnt].a=a[i];
		L[cnt].b=a[last[i]];
		L[cnt].ang=atan2(L[cnt].b.y-L[cnt].a.y,L[cnt].b.x-L[cnt].a.x);
	}
	cnt++;
	L[cnt].a=a[n];
	L[cnt].b=a[1];
	L[cnt].ang=atan2(L[cnt].b.y-L[cnt].a.y,L[cnt].b.x-L[cnt].a.x);
	sort(L+1,L+cnt+1,cmp);
	int tot=0;
	L[0].ang=-707;
	for(i=1;i<=cnt;i++)
	if(L[i].ang!=L[i-1].ang)
	tot++,L[tot]=L[i];
	cnt=tot;
	h=t=1;q[1]=L[1];
	for(i=2;i<=cnt;i++)
	{
		while(h<t&&left(p[t-1],L[i])) t--;
		while(h<t&&left(p[h],L[i])) h++;
		t++;q[t]=L[i];
		if(h<t) p[t-1]=jiao(q[t-1],q[t]);
	}
	while(h<t&&left(p[t-1],q[h])) t--;
	p[t]=jiao(q[t],q[h]);
	t++;p[t]=p[h];
	double ans=0;
	for(i=h;i<t;i++)
	ans+=dis(p[i],p[i+1]);
	printf("%.9lf",ans-dis(a[1],a[n]));
}

發佈了170 篇原創文章 · 獲贊 42 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章