hdu 3126 Nova【计算几何+二分+最大流Dinic】好题

Nova

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1349    Accepted Submission(s): 253

Problem Description

The Lich is a powerful hero that he can kill a wisp with his skill Frost Nova. The Burning Legion wants to conquer the forest so they sent some liches to kill all the wisps. A lich can kill a wisp once he could see the wisp and the wisp in his attack range. So the lich can attack a wisp when the distance between them is less than or equal to specific R and no trees are on the segment between the lich and wisp. Each lich has a cool down time that once he used Frost Nova he has to wait a few seconds for the next attack. Different liches may have different attack range and cool down time. The Lich King is the leader of the Burning Legion and he wants to arrange the attack order so the liches can wipe out all the wisps as soon as possible.

Input

The first line consists of an integer T, indicating the number of test cases.
The first line of each case consists of three integers N, M, K, indicating the number of lich, the number of wisps and the number of trees. The next N lines, each line consists of four integers x, y, r, t indicating the coordinate of that a lich, the radius of the attack range that lich’s Frost Nova can reach and the value of cool down time. The next M lines, each line consists of two integers x, y indicating the coordinate of each wisp. The last K lines, each line consists of three integers x, y, r, indicating the coordinate and radius of a tree. A lich cannot attack a wisp if the segment between them has a common point with the tree. The lich, wisp and trees will not overlap with each other.

Output

Output the minimum time lich need to kill all the wisps on a single line, or -1 if lich cannot kill all the wisps.

Constrains
0 < T <= 20
0 <= N, M, K <= 200
-10000 <= x, y <= 10000
0 <= r, t <= 10002

Sample Input

1

2 3 1

-100 0 100 3

100 0 100 5

-100 -10

100 10

110 11

5 5 10

Sample Output

5

Source

2009 Asia Wuhan Regional Contest Online

Recommend

lcy   |   We have carefully selected several similar problems for you:  3124 3127 3125 3123 3118 

 

题目大意:

一共有N个巫师,一共有M个敌人,K棵树。

给你N个巫师的坐标,攻击范围半径,以及攻击周期,再给你M个敌人的坐标,以及K棵树的坐标以及其半径。

如果敌人在巫师的攻击范围之内,那么如果其两点之间连线间不会有树阻挡,那么这个巫师就可以消灭这个敌人。问消灭掉所有敌人需要的最少的时间。如果不能消灭所有的敌人,输出-1。


思路(码农题):


1、首先我们O(N*M*K)的预处理出这M个敌人都能被哪些巫师杀死。并且记录起来,(代码中抄袭了别人的计算几何部分的板子,计算几何蒟蒻T T)。


2、然后我们考虑这样一个单调性:随着时间的增多,那么其最优分配情况能够杀死的敌人也就越多,其满足单调性,显然我们能够二分这个时间,来处理这个问题。考虑当前二分到的值mid:

①设定源点,连入每一个敌人,流设定为1.

②设定汇点,将每个巫师连入汇点,流设定为其时间/攻击周期+1.

③将每个敌人连入能够杀死其自己的巫师节点,流设定为1.

然后跑最大流,如果最大流==m,那么说明当前最优情况是可以在mid这个时间内杀死所有敌人的。

然后继续二分,记录最优解即可。


Ac代码:


#include<stdio.h>
#include<queue>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
struct node
{
    int from;
    int to;
    int w;
    int next;
}e[20000000];
struct Point
{
    double x,y;
}p[10];
struct node1
{
    int x,y,r,z;
}a[6000];
int divv[6000];
int cur[6000];
int head[6000];
int dian[600][2];
int tree[600][3];
int map[300][300];
const double eps=1e-7;
int n,m,k,cont,ss,tt;
int add(int from,int to,int w)
{
    e[cont].to=to;
    e[cont].w=w;
    e[cont].next=head[from];
    head[from]=cont++;
}
void Getmap(int mid)
{
    memset(head,-1,sizeof(head));
    cont=0;
    ss=n+m+1;
    tt=ss+1;
    for(int i=0;i<m;i++)
    {
        add(ss,i,1);
        add(i,ss,0);
    }
    for(int i=0;i<n;i++)
    {
        add(i+m,tt,mid/a[i].z+1);
        add(tt,i+m,0);
    }
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(map[i][j]==1)
            {
                add(i,j+m,1);
                add(j+m,i,0);
            }
        }
    }
}
int makedivv()
{
    queue<int >s;
    s.push(ss);
    memset(divv,0,sizeof(divv));
    divv[ss]=1;
    while(!s.empty())
    {
        int u=s.front();
        if(u==tt)return 1;
        s.pop();
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            if(w&&divv[v]==0)
            {
                divv[v]=divv[u]+1;
                s.push(v);
            }
        }
    }
    return 0;
}
int Dfs(int u,int maxflow,int tt)
{
    if(u==tt)return maxflow;
    int ret=0;
    for(int &i=cur[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        int w=e[i].w;
        if(w&&divv[v]==divv[u]+1)
        {
            int f=Dfs(v,min(maxflow-ret,w),tt);
            e[i].w-=f;
            e[i^1].w+=f;
            ret+=f;
            if(ret==maxflow)return ret;
        }
    }
    return ret;
}
int Slove(int mid)
{
    Getmap(mid);
    int ans=0;
    while(makedivv()==1)
    {
        memcpy(cur,head,sizeof(head));
        ans+=Dfs(ss,0x3f3f3f3f,tt);
    }
    if(ans==m)return 1;
    else return 0;
}
double Distance(Point a, Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)*1.0 + 1.0*(a.y-b.y)*(a.y-b.y));
}

double xmult(Point p1, Point p2, Point p)
{
    return (p1.x-p.x)*(p2.y-p.y) - (p2.x-p.x)*(p1.y-p.y);
}
double disptoseg(Point p, Point a ,Point b)
{
    Point t = p;
    t.x += a.y-b.y, t.y += b.x-a.x;
    if(xmult(a,t,p)*xmult(b,t,p)>eps)
        return Distance(p,a) < Distance(p,b)? Distance(p,a) : Distance(p,b);
    return fabs(xmult(p, a, b))/Distance(a, b);
}
void init()
{
    memset(map,0,sizeof(map));
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {
            p[0].x=(double)(dian[i][0]);
            p[0].y=(double)(dian[i][1]);
            p[1].x=(double)(a[j].x);
            p[1].y=(double)(a[j].y);
            double rr=(double)(a[j].r);
            if(Distance(p[0],p[1])<=rr)
            {
                int flag=0;
                for(int kk=0;kk<k;kk++)
                {
                    p[2].x=(double )(tree[kk][0]);
                    p[2].y=(double )(tree[kk][1]);
                    double tmpp=(double )(tree[kk][2]);
                    if(disptoseg(p[2],p[0],p[1])<=tmpp)
                    {
                        flag=1;
                    }
                }
                if(flag==0)
                {
                    map[i][j]=1;
                }
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        int maxn=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].r,&a[i].z);
            maxn=max(a[i].z,maxn);
        }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&dian[i][0],&dian[i][1]);
        }
        for(int i=0;i<k;i++)
        {
            scanf("%d%d%d",&tree[i][0],&tree[i][1],&tree[i][2]);
        }
        init();
        int mid;
        int ans=-1;
        int l=0;
        int r=m*maxn+100;
        while(r>=l)
        {
            mid=(l+r)/2;
            if(Slove(mid)==1)
            {
                r=mid-1;
                ans=mid;
            }
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值