hdu4606 Occupy Cities简单计算几何+floyd+最小路径覆盖+二分答案

来源:互联网 发布:python输入ctrl c 编辑:程序博客网 时间:2024/06/05 02:56

借鉴这里:http://www.cnblogs.com/wangfang20/archive/2013/07/25/3213628.html

有n个城市,m个边界线,p名士兵。现在士兵要按一定顺序攻占城市,不能穿过一些线段。士兵有一个容量为K的背包装粮食,士兵如果攻占城市,就能装满背包。从城市到城市消耗的粮食等于两城市的距离,如果距离大于士兵当前的背包的容量,士兵就不能走这条路。求p个士兵攻占完所有城市所需要的最小背包容量k。

二分答案  , 将所有的直线的两个端点和城市混在一起,将能直接到达的两个点连线,求一次floyd最短路径。二分枚举bag容量,只需要判断最小路径覆盖是否小于等于p,就是最少需要多少个士兵才能全部占领

#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define clr(x) memset(x,0,sizeof(x));#define INF 0x1f1f1f1f#define maxn 510#define maxm 510#define eps 1e-6struct Point{    double x;    double y;}city[maxn];struct Edge{    Point a,b;}edge[maxm];int ord[maxn];double d[maxn+maxm*2][maxn+maxm*2];int n,m,p;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);}double Dis(Point a,Point b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}bool isIntersected(Point s1,Point e1,Point s2,Point e2){   //判断线段是否相交(非规范相交)   return multi(s1,e1,s2)*multi(s1,e1,e2)<-eps&&          multi(s2,e2,s1)*multi(s2,e2,e1)<-eps;}int g[maxn][maxn];int v[maxn];int link[maxn];int find(int k){    int i;    for(i=1;i<=n;i++){        if(g[k][i]&&!v[i]){            v[i]=1;            if(link[i]==0||find(link[i])){                link[i]=k;                return 1;            }        }    }    return 0;}int maxmatch(){    int i;    clr(link);    int res=0;    for(i=1;i<=n;i++){        clr(v);        if(find(i))res++;    }    return n-res;}int main(){    int T,tot,i,j,k;    scanf("%d",&T);    while(T--){       scanf("%d%d%d",&n,&m,&p);       for(i=1;i<=n;i++)            scanf("%lf%lf",&city[i].x,&city[i].y);        tot=n;        for(i=1;i<=m;i++){            scanf("%lf%lf%lf%lf",&edge[i].a.x,&edge[i].a.y,&edge[i].b.x,&edge[i].b.y);            city[++tot].x=edge[i].a.x;city[tot].y=edge[i].a.y;            city[++tot].x=edge[i].b.x;city[tot].y=edge[i].b.y;        }        for(i=1;i<=n;i++)            scanf("%d",&ord[i]);        for(i=1;i<=tot;i++)            for(j=1;j<=tot;j++)                d[i][j]=INF;        for(i=1;i<tot;i++){            for(j=i+1;j<=tot;j++){                int flag=0;                for(k=1;k<=m;k++)                if(isIntersected(city[i],city[j],edge[k].a,edge[k].b)){                    flag=1;break;                }                if(flag==0)d[i][j]=d[j][i]=Dis(city[i],city[j]);            }        }        for(k=1;k<=tot;k++)            for(i=1;i<=tot;i++)                for(j=1;j<=tot;j++){                    d[i][j]=min(d[i][j],d[i][k]+d[k][j]);                }        double maxlen=0.0;        for(i=1;i<=n;i++)        for(j=1;j<=n;j++){            if(d[i][j]<INF)maxlen=max(d[i][j],maxlen);        }        double mid,l=0,r=maxlen;        while(r-l>eps){            mid=(l+r)/2;            clr(g);            for(i=1;i<n;i++)                for(j=i+1;j<=n;j++){                if(d[ord[i]][ord[j]]<=mid)                    g[ord[i]][ord[j]]=1;            }            if(maxmatch()<=p)r=mid;            else l=mid;        }        printf("%.2lf\n",r);    }    return 0;}


原创粉丝点击