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;
}

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