HLG 1238 Nova【二分+二分图多重匹配+圆与线段相交判断】

题意: 有n 个小巫师,还有 m 个小精灵 ,还有 K 个大树,巫师可以用 霜冻新星杀死小精灵,但是每使用一次都有一定

   的技能冷却时间,而且小精灵必须在攻击范围内。

分析: 二分答案,即枚举符合条件的时间,满足所有小精灵被KO,由于每个巫师能够杀死多个小精灵,所以可以用到二分

          图多重匹配,如果所有小精灵都找到匹配,那么该时间符合, 最麻烦的是建图,两个人之间必须不能有树阻挡,在

         计算两个人所在线段与 树相交的时候 可以先计算点(树的坐标)到线段(巫师与小精灵连线)的最短距离,如果该

         距离小于树的半径,那么该巫师和小精灵能够形成匹配。

 

View Code
#include<stdio.h>
#include<string.h>
#include<math.h>
#define clr(x) memset(x,0,sizeof(x))
int cap;
int map[202][202];
int link[202][202];
int vlink[202];
int v[202];
int tot;
int n,m,K;
double lx[202],ly[202],lr[202];
int t[202];
double tx[202],ty[202],tr[202];
double wx[202],wy[202];
int find(int x)
{
    int i,j;
    for(i=0;i<n;i++)
    {
        if(map[x][i]&&!v[i])
        {
            v[i]=1;
            if(t[i]==0||vlink[i]<=cap/t[i])
            {
                link[i][vlink[i]++]=x;
                return 1;
            }
            for(j=0;j<vlink[i];j++)
                if(find(link[i][j]))
                {
                    link[i][j]=x;
                    return 1;
                }
        }
    }
    return 0;
}
bool ok()
{
    int i,sum=0;
    clr(vlink);
    for(i=0;i<m;i++)
    {
        clr(v);
        if(find(i))
            sum++;
        else break;
    }
    if(sum==m)
        return 1;
    return 0;
}
double dis(double x1,double y1,double x2,double y2)
{   return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); }
double mul(double x1,double y1,double x2,double y2)
{   return x1*y2-x2*y1;   }
double fa(double x)
{   return x>0?x:-1*x;    }

bool sec(int i,int j,int k)
{
    double s=fa(mul(wx[j]-lx[i],wy[j]-ly[i],tx[k]-lx[i],ty[k]-ly[i]));
    double t1=dis(lx[i],ly[i],tx[k],ty[k]);
    double t2=dis(wx[j],wy[j],tx[k],ty[k]);
    double t3=dis(lx[i],ly[i],wx[j],wy[j]);
    double dd=s/t3;
    double tm1=sqrt(t1*t1-dd*dd);
    double tm2=sqrt(t2*t2-dd*dd);
    double d;
    if(tm1>t3||tm2>t3)
    {
        if(t1>t2)
            d=t2;
        else d=t1;
    }
    else d=dd;
    if(d<=tr[k])
        return true;
    return false;
}
bool in(int i,int j)
{
    if(dis(lx[i],ly[i],wx[j],wy[j])<=lr[i])
       return true;
    return false;
}
int main()
{
    //freopen("D:ce.txt","r",stdin);
    int i,j,k,T,low,high,tmp;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&K);
        tmp=0;
        for(i=0;i<n;i++)
        {
            scanf("%lf%lf%lf%d",&lx[i],&ly[i],&lr[i],&t[i]);
            if(t[i]>tmp)
                tmp=t[i];
        }
        for(i=0;i<m;i++)
            scanf("%lf%lf",&wx[i],&wy[i]);
        for(i=0;i<K;i++)
            scanf("%lf%lf%lf",&tx[i],&ty[i],&tr[i]);
        clr(v);
        clr(map);
        for(i=0;i<n;i++)
            for(j=0;j<m;j++)
            {
                if(in(i,j))
                {
                    for(k=0;k<K;k++)
                        if(sec(i,j,k))
                            break;
                    if(k==K)
                    {
                        v[j]=1;
                        map[j][i]=1;
                    }
                }
            }
        for(i=0;i<m;i++)
            if(!v[i])
                break;
        if(i!=m)
        {
            printf("-1\n");
            continue;
        }
        low=0;
        high=tmp*m;
        while(low<high)
        {
            cap=(low+high)>>1;
            if(ok())
                high=cap;
            else low=cap+1;
        }
        printf("%d\n",low);
    }
    return 0;
} 
 
 
 

 

posted @ 2012-06-25 15:19  'wind  阅读(244)  评论(0编辑  收藏  举报