ZOJ 3640--Missile【二分查找 && 最大流dinic && 经典建图】

Missile


Time Limit: 2 Seconds     
Memory Limit: 65536 KB



You control N missile launching towers. Every tower has enough missiles, but for each tower only one missile can be launch at the same time. Before the launching, every missile needT1 seconds to leave the tower. Assume that all
the missiles have the same speedV, and it would fly along the shortest path to the target. You can just consider the horizontal distance and ignore the height. You can consider the time equal to distance / V (minutes). The missile can immediately
destroy the target when it reached. Besides, for the same tower, after launching a missile, it needT2 minutes to prepare for the next one.

Now, give you the coordinate position of N missile launching towers andM targets,T1,
T2 and V, you should find the minimum minutes to destroy all the targets.

Input

The input will consist of about 10 cases. The first line of each case contains five positive integer numbersN,M,
T1, T2 and V, decribed as above. The nextM lines contains two integer numbers indicating the coordinate ofM targets. The continueingN lines contains two integer numbers indicating the
coordinate ofN towers.

To all the cases, 1 ≤ N ≤ 50, 1 ≤ M ≤ 50

The absolute value of all the coordinates will not exceed 10000, T1,T2,V will not exceed 2000.

Output

For each case, the output is only one line containing only one real number with six digits precision (after a decimal point) indicating the minimum minutes to destroy all the targets.

Sample Input

3 3 30 20 1
0 0
0 50
50 0
50 50
0 1000
1000 0

Sample Output

91.500000

题意:用N个导弹发射塔攻击M个目标。每个导弹发射塔只能同时为一颗导弹服务,发射一颗导弹后需要T1(这里用的是秒)的时间才能离开当前的导弹发射塔,一颗导弹从发射到击中目标的时间与目标到发射塔的距离有关(直线距离),每颗导弹发射完成之后发射塔需要T2的时间准备下一个。现在给出N个导弹发射塔和M个目标的位置坐标以及T1,T2,V,问用这N个导弹发射塔最少需要多少时间可以击毁所有M个目标。

具体实现

一:对每一个导弹发射器,它击中一个目标共有M种情况:分别为在该发射塔第一次发射、第二次发射、第三次发射...一直到第M次发射。因此我们可以把每一个导弹发射塔拆分成M个发射塔,它们与同一个目标的距离是一样的,唯一不同是T1、T2的花销占时不一样。

二:这样的话我们就得到了N*M个点发射器到 M个目标的映射,所表示的关系是当前发射塔击中目标的耗时。

三:设立超级源点0,超级汇点 N * M + M + 1。

四:超级源点到每个目标引一条容量为1的边,每个发射塔(拆分后的)到超级汇点引一条容量为1的边,按若小于当前查询时间的关系(同匹配建边)建边容量为1。

然后跑最大流,判断最大流是否为M。 接着二分查找。

以上解析来自宇哥哥的博客:笑着走完自己的路

笑着走完自己的

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define INF 0x3f3f3f3f
#define maxn 5000
#define maxm 500000
using namespace std;

int head[maxn], cur[maxn], cnt;
int dist[maxn], vis[maxn];
struct node {
	int u, v, cap, flow, next;
};

struct NODE{
	double x, y;
};

node edge[maxm];
NODE tower[60];
NODE target[60];
int N, M;
double T1, T2, V;
double map[60][60];
double Time[3000][60];

double change(NODE a, NODE b){
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

void init(){
	cnt = 0;
	memset(head, -1, sizeof(head));
}

void add(int u, int v, int w){
	node E1 = {u, v, w, 0, head[u]};
	edge[cnt] = E1;
	head[u] = cnt++;
	node E2 = {v, u, 0, 0, head[v]};
	edge[cnt] = E2;
	head[v] = cnt++;
}

void getmap(double max_min){
	int i, j;
	for(i = 1; i <= N * M; ++i)
		add(0, i, 1);
	for(i = N * M + 1; i <= N * M + M; ++i)
		add(i, N * M + M + 1, 1);
	for(i = 1; i <= N * M; ++i)
		for(j = 1; j <= M; ++j)
			if(Time[i][j] <= max_min)
				add(i, j + N * M, 1);
}

bool BFS(int st, int ed){
    queue<int>q;
    memset(vis, 0, sizeof(vis));
    memset(dist, -1, sizeof(dist));
    q.push(st);
    vis[st] = 1;
    dist[st] = 0;
    while(!q.empty()){
        int u = q.front();
        q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next){
            node E = edge[i];
            if(!vis[E.v] && E.cap > E.flow){
                vis[E.v] = 1;
                dist[E.v] = dist[u] + 1;
                if(E.v == ed) return true;
                q.push(E.v);
            }
        }
    }
    return false;
}  

int DFS(int x, int ed, int a){
    if(a == 0 || x == ed)
        return a;
    int flow = 0, f;
    for(int &i = cur[x]; i != -1; i =edge[i].next){
        node &E = edge[i];
        if(dist[E.v] == dist[x] + 1 && (f = DFS(E.v, ed, min(a, E.cap - E.flow))) > 0){
            E.flow += f;
            edge[i ^ 1].flow -= f;
            flow += f;
            a -= f;
            if(a == 0) break;
        }
    }
    return flow;
}  

int maxflow (int st, int ed){
    int flowsum  = 0;
    while(BFS(st, ed)){
        memcpy(cur, head, sizeof(head));
        flowsum += DFS(st, ed, INF);
    }
    return flowsum;
}  

int main (){
	while(scanf("%d%d%lf%lf%lf", &N, &M, &T1, &T2, &V) != EOF){
		T1 = T1 / 60;
		int i, j, k;
		for(j = 1; j <= M; ++j)
			scanf("%lf%lf", &target[j].x, &target[j].y);
		for(i = 1; i <= N; ++i)
			scanf("%lf%lf", &tower[i].x, &tower[i].y);
		for(i = 1; i <= N; ++i)
			for(j = 1; j <= M; ++j)
				map[i][j] = change(tower[i], target[j]);
		for(i = 1; i <= N; ++i)
			for(k = 1; k <= M; ++k){
				for(j = 1; j <= M; ++j)
				Time[(i - 1) * M + k][j] = T1 * k + T2 * (k - 1) + map[i][j] / V;
			}
		double l = 0.0, r = 200000000000.0, mid;
		while(r - l >= 1e-8){
			mid = (l + r) / 2;
			init();
			getmap(mid);
			if(maxflow(0, N * M + M + 1) >= M)
				r = mid;
			else
				l = mid;
		}
		printf("%.6lf\n", r);
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 13:02:51

ZOJ 3640--Missile【二分查找 && 最大流dinic && 经典建图】的相关文章

POJ 3422 HDU 2686,3376 费用流拆点建图

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3376 http://acm.hdu.edu.cn/showproblem.php?pid=2686 http://poj.org/problem?id=3422 POJ 3422为从矩阵左上角走到右下角,最多走k次,每个格子里的数字只能算一次,后面可以重复经过,求经过的各个数字的和的最大值. 拆点,入点向出点连流量为1,费用为当前格子负值的边,向下方,右方连边,流量为k,费用为0,起点连流量为1,

HDU2732Leapin&amp;#39; Lizards(最大流SAP,建图---折点法)

Leapin' Lizards Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1531    Accepted Submission(s): 623 Problem Description Your platoon of wandering lizards has entered a strange room in the labyr

HDU2732Leapin&#39; Lizards(最大流SAP,建图---折点法)

Leapin' Lizards Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1531    Accepted Submission(s): 623 Problem Description Your platoon of wandering lizards has entered a strange room in the labyr

POJ 2391--Ombrophobic Bovines【拆点 &amp;&amp; 二分 &amp;&amp; 最大流dinic &amp;&amp; 经典】

Ombrophobic Bovines Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16460   Accepted: 3593 Description FJ's cows really hate getting wet so much that the mere thought of getting caught in the rain makes them shake in their hooves. They h

POJ 3281 Dining (网络流最大流 拆点建图 Edmonds-Karp算法)

Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10159   Accepted: 4676 Description Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others. Farmer John has cooked fabulo

HDU 3572 【最大流 &amp;&amp; 时间区间建图】

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5398    Accepted Submission(s): 1742 Problem Description Our geometry princess XMM has stoped her study in computational geometry t

HDU 3376--Matrix Again【最大费用最大流 &amp;&amp; 经典建图】

Matrix Again Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 3457    Accepted Submission(s): 1020 Problem Description Starvae very like play a number game in the n*n Matrix. A positive intege

POJ 3498【最大流+拆点建图】

题意: 在X,Y坐标系中有N(N<=100)个冰块...有些冰块上有若干只企鹅..每只企鹅一次最多跳M距离..一个冰块在有Mi个企鹅离开..就会消失..问有哪些冰块可以作为集合点..就是所有企鹅都能成功到这个冰块上来. 这个题建图比较有意思. 把每块冰分成两个点i和i+n. i表示进入i冰块的点(可以有无数企鹅过来,所以从别的冰到i有边,容量为INF) i+n表示从i冰块出去的点(最多只能有Mi企鹅从这跳出去,所以从i到i+n有边,且容量为Mi) 从源点S到i有边(S, i, i点初始企鹅数).

POJ 2112 Optimal Milking 最优挤奶方案 Floyd算法+二分查找+最大流

题目链接:POJ 2112 Optimal Milking Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 12446   Accepted: 4494 Case Time Limit: 1000MS Description FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among