/*
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;
}
hdu 4606 Occupy Cities - 計算幾何 + 最短路 + 最小路徑覆蓋
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.