hdu 4606 Occupy Cities - 计算几何 + 最短路 + 最小路径覆盖

/*
hdu 4606 Occupy Cities

题意:n个城市,m条障碍物,p个士兵,城市之间的路可以任意走,但是不能跨越障碍。
	p个士兵分别按顺序占领城市,城市内有补给,士兵的消耗等于路程的长度。
	问:为了完成任务,士兵的揹包最小为多大?

这是一个最小路径覆盖问题,每个士兵都可以走出一条线来。
说道顺序,建图是只能从顺序靠前的城市向靠后的城市建边,这样就保证了单个士兵所走的城市复合顺序。
士兵之间的顺序则无需考虑,因为若某个城市需要先占领,就让那个士兵去占领就可以了,其他士兵等待。

在求城市之间最短距离的时候用到了floyd


*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <math.h>
#define eps 1e-8
#define zero(x) (((x)>0?(x):-(x))<eps)
struct point
{
    double x,y;
};
struct line
{
    point a,b;
};
line xian[110];
point dian[320];
int seq[320];
double map[320][320];
int n,m,p;
//两点距离
double distance(point p1,point p2)
{
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
//叉积
double multi(point p0, point p1, point p2)
{
    return ( p1.x - p0.x )*( p2.y - p0.y )-( p2.x - p0.x )*( p1.y - p0.y );
}

inline double max(double a,double b)
{
	if(a>b) return a;
	return b;
}

inline double min(double a,double b)
{
	if(a<b) return a;
	return b;
}
//相交返回true,否则为false, 接口为两线段的端点
bool isIntersected(point s1,point e1, point s2,point e2)
{
    return  (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(s1,s2,e1)*multi(s1,e1,e2)>0) &&
            (multi(s2,s1,e2)*multi(s2,e2,e1)>0);
}

int noblock(int a,int b)
{
	int i;
	for(i=0;i<m;++i)
	{
		if(isIntersected(dian[a],dian[b],xian[i].a,xian[i].b))
		{
			return 0;
		}
	}
	return 1;
}
int ke[320][320];
int match[150],vis[105];
int zou[105][105];
int dfs(int i)  
{  
    for(int j=1;j<=n;++j)  
    {  
		if(ke[i][j]==0) continue;
        if(!vis[j])  
        {  
            vis[j]=1;  
            if(match[j]==-1||dfs(match[j]))  
            {  
                match[j]=i;  
                return 1;  
            }  
        }  
    }  
    return 0;  
}  
int ok(double shang)
{
	memset(ke,0,sizeof(ke));
	int i,j;
	for(i=1;i<=n+m*2;++i)
	{
		for(j=1;j<=n+m*2;++j)
		{
			if(i==j) continue;
			if(map[i][j]<=shang&&seq[i]<seq[j])
			{
				ke[i][j]=1;
			}
		}
	}

	memset(match,-1,sizeof(match));  
	int a=0;
	for(i=1;i<=n;i++)  
	{  
		memset(vis,0,sizeof(vis));  
		if(dfs(i))  
			a++;  
	}
	if((n-a)<=p) return 1;
	return 0;
}
int main()
{
	int t,i,j,k;
	double shang,xia,zhong;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&n,&m,&p);
		for(i=1;i<=n;++i)
		{
			scanf("%lf%lf",&dian[i].x,&dian[i].y);
		}
		for(j=0;i<=n+m*2;i=i+2,++j)
		{
			scanf("%lf%lf%lf%lf",&dian[i].x,&dian[i].y,&dian[i+1].x,&dian[i+1].y);
			xian[j].a=dian[i];
			xian[j].b=dian[i+1];
		}
		for(i=1;i<=n;++i)
		{
			scanf("%d",&k);
			seq[k]=i;
		}
		for(i=1;i<=n+m*2;++i)
		{
			for(j=i+1;j<=n+m*2;++j)
			{
				if(noblock(i,j))
				{
					map[i][j]=map[j][i]=distance(dian[i],dian[j]);
				}else
				{
					map[i][j]=map[j][i]=999999999;
				}
			}
			map[i][i]=999999999;
		}
		for(k=1;k<=n+m*2;++k)
		{
			for(i=1;i<=n+m*2;++i)
			{
				for(j=1;j<=n+m*2;++j)
				{
					map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
				}
			}
		}
		shang=0;
		for (i=1;i<=n+m*2;i++)
		{
			for (j=i+1;j<=n+m*2;j++)
			{
				shang=max(shang,map[i][j]);
			}
		}
		xia=0;
		while((shang-xia)>eps)
		{
			zhong=(shang+xia)/2;
			if(ok(zhong))
			{
				shang=zhong;
			}else
			{
				xia=zhong;
			}
		}
		printf("%.2lf\n",xia);
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章