zoukankan      html  css  js  c++  java
  • P4048 【[JSOI2010]冷冻波】

    题意:

    WJJ喜欢“魔兽争霸”这个游戏。在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵。我们认为,巫妖和小精灵都可以看成是平面上的点。

    当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以瞬间杀灭一个小精灵。

    在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放。不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以杀死一个小精灵。

    现在巫妖的头目想知道,若从0时刻开始计算,至少需要花费多少时间,可以杀死所有的小精灵?

    sloution

    因为求的是最小的时间,考虑二分答案。

    我们现在时间确定了,那么每个巫师能打死的小精灵的数量也是确定的。

    考虑用网络流求解。

    从源点向巫师连一条容量为巫师能打死的小精灵的数量,从每个巫师向他能打到的小精灵连一条容量为 (1) 的边。

    再由每个小精灵向汇点连一条容量为 (1) 的边。

    这样跑出来的最大流,就是我们最多能打死的精灵的数量。

    现在想想,怎么求每个巫师能打死那个精灵。 (n^3) 暴力枚举一下。

    因为每棵树的范围是一个圆,所以就相当于问你这个圆是否和巫师和小精灵的连线有交。

    可以求出圆心到这条线段的最小距离,在和半径比较即可。

    此外,还应该判断小精灵是否在巫师的攻击范围内,即点是否在圆内。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<cstring>
    using namespace std;
    const double eps = 1e-8;
    const int inf = 1e7+10;
    const int N = 2010;
    int n,m,k,u,v,s,t,res,tot = 1;
    int head[N],dep[N],tim[N],r[N],R[N];
    bool used[N][N];
    struct node
    {
    	int to,net,w;
    }e[100010];
    struct point
    {
    	int x,y;
    	point(){}
    	point(int a,int b){x = a, y = b;}
    }c[N],p[N],tr[N];
    typedef point Vector;
    point operator + (point a,point b){return point(a.x+b.x,a.y+b.y);}
    point operator - (point a,point b){return point(a.x-b.x,a.y-b.y);}
    point operator * (point a,double k){return point(a.x*k,a.y*k);}
    double Dot(point a,point b){return a.x*b.x+a.y*b.y;}
    double Cro(point a,point b){return a.x*b.y-a.y*b.x;}
    double dis(point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
    double dis_PS(point p,point A,point B)
    {
    	if(Dot(p-A,B-A) < 0) return dis(p,A);
    	if(Dot(p-B,A-B) < 0) return dis(p,B);
    	return abs(Cro(A-p,B-p))/dis(A,B);
    }
    void add(int x,int y,int w)
    {
    	e[++tot].to = y;
    	e[tot].w = w;
    	e[tot].net = head[x];
    	head[x] = tot;
    }
    bool bfs()
    {
    	queue<int> q;
    	for(int i = 0; i <= t; i++) dep[i] = 0;
    	q.push(s); dep[s] = 1;
    	while(!q.empty())
    	{
    		int x = q.front(); q.pop();
    		for(int i = head[x]; i; i = e[i].net)
    		{
    			int to = e[i].to;
    			if(e[i].w && !dep[to])
    			{
    				dep[to] = dep[x] + 1;
    				q.push(to);
    				if(to == t) return 1;
    			}
    		}
    	}
    	return 0;
    }
    int dinic(int x,int flow)
    {
    	if(x == t || !flow) return flow;
    	int rest = flow, val = 0;
    	for(int i = head[x]; i && rest; i = e[i].net)
    	{
    		int to = e[i].to;
    		if(!e[i].w || dep[to] != dep[x] + 1) continue;
    		val = dinic(to,min(rest,e[i].w));
    		if(val == 0) dep[to] = 0;
    		e[i].w -= val; e[i^1].w += val; rest -= val;
    	}
    	return flow - rest;
    }
    bool judge(int mid)
    {
    	s = 0, t = n+m+1, tot = 1, res = 0;
    	memset(head,0,sizeof(head));
    	for(int i = 1; i <= n; i++) add(s,i,(mid/tim[i])+1), add(i,s,0);
    	for(int i = 1; i <= m; i++) add(i+n,t,1), add(t,i+n,0);
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= m; j++)
    		{
    			if(used[i][j]) add(i,j+n,1), add(j+n,i,0);
    		}
    	}
    	int flow = 0;
    	while(bfs())
    	{
    		while(flow = dinic(s,inf)) res += flow;
    	}
    	return res >= m;
    }
    int main()
    {
    	scanf("%d%d%d",&n,&m,&k);
    	for(int i = 1; i <= n; i++) scanf("%d%d%d%d",&c[i].x,&c[i].y,&r[i],&tim[i]);
    	for(int i = 1; i <= m; i++) scanf("%d%d",&p[i].x,&p[i].y);
    	for(int i = 1; i <= k; i++) scanf("%d%d%d",&tr[i].x,&tr[i].y,&R[i]);
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= m; j++)
    		{
    			int flag = 0;
    			double tmp = dis(c[i],p[j]);
    			if(tmp > r[i]) continue;
    			for(int l = 1; l <= k; l++) 
    			{
    				double tmp = dis_PS(tr[l],c[i],p[j]);
    				if(tmp <= R[l]) flag = 1;
    			}
    			if(flag == 0) used[i][j] = 1;
    		}
    	}
    	int L = 0, R = 500000, ans = -1;
    	while(L <= R)
    	{
    		int mid = (L + R)>>1;
    		if(judge(mid)) 
    		{
    			R = mid - 1;
    			ans = mid;
    		}
    		else L = mid + 1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    mysql 单表下的字段操作_查询
    mysql 表的操作
    mysql 单表下的字段操作
    mysql库的操作
    vim 复制&粘贴
    将系统剪贴板的内容粘贴到vim
    nc替代ping
    kali 将家目录下的中文文件名修改成英文
    Shiro反序列化漏洞检测、dnslog
    mac命令行切换python版本
  • 原文地址:https://www.cnblogs.com/genshy/p/14350657.html
Copyright © 2011-2022 走看看