您的位置:首页 > 其它

【bzoj3035】【codevs2490】导弹防御塔 二分+匈牙利 || 二分+dinic

2016-03-02 11:20 423 查看

题目描述 Description

  Freda的城堡——

  “Freda,城堡外发现了一些入侵者!”

  “喵…刚刚探究完了城堡建设的方案数,我要歇一会儿嘛lala~”

  “可是入侵者已经接近城堡了呀!”

  “别担心,rainbow,你看呢,这是我刚设计的导弹防御系统的说~”

  “喂…别卖萌啊……”

  Freda控制着N座可以发射导弹的防御塔。每座塔都有足够数量的导弹,但是每座塔每次只能发射一枚。在发射导弹时,导弹需要T1秒才能从防御塔中射出,而在发射导弹后,发射这枚导弹的防御塔需要T2分钟来冷却。

  所有导弹都有相同的匀速飞行速度V,并且会沿着距离最短的路径去打击目标。计算防御塔到目标的距离Distance时,你只需要计算水平距离,而忽略导弹飞行的高度。导弹在空中飞行的时间就是 (Distance/V) 分钟,导弹到达目标后可以立即将它击毁。

  现在,给出N座导弹防御塔的坐标,M个入侵者的坐标,T1、T2和V,你需要求出至少要多少分钟才能击退所有的入侵者。

输入描述 Input Description

  第一行五个正整数N,M,T1,T2,V。

  接下来M行每行两个整数,代表入侵者的坐标。

  接下来N行每行两个整数,代表防御塔的坐标。

输出描述 Output Description

  输出一个实数,表示最少需要多少分钟才能击中所有的入侵者,四舍五入保留六位小数。

样例输入 Sample Input

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


样例输出 Sample Output

91.500000


数据范围及提示 Data Size & Hint

  对于40%的数据,N,M<=20.

  对于100%的数据, 1≤N≤50, 1≤M≤50,坐标绝对值不超过10000,T1,T2,V不超过2000.

来源:Nescafe 19

Orzlyd

CH挂了,tyvj评测机评的和我手测不一样,幸亏codevs有…bzoj的还是T所以我敲个dinic去看看…

不好求极值,转为二分。

二分答案T,看看T个时间内能发多少个导弹,能发多少个就拆成多少个点,然后若某个导弹a时刻发出去,需要b时刻才能打中目标,那么这个点和目标连一条边,然后跑个匈牙利看看是不是完全匹配即可

还有就是论认真读题的重要性…题目中t1的单位是秒,t2和答案的单位是分钟…坑爹啊我半天没看见

……卡常数……卡二分上界……我不想说什么了……

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;

const double INF = 30000;
const int SZ = 1000010;

int n,m;
double t1,t2;

double t[233][233];

int head[SZ],nxt[SZ],tot = 0,to[SZ];

void build(int f,int t)
{
to[++ tot] = t;
nxt[tot] = head[f];
head[f] = tot;
}

bool vis[SZ];
int match[SZ];
bool dfs(int u)
{
for(int i = head[u];i;i = nxt[i])
{
int v = to[i];
if(!vis[v])
{
vis[v] = 1;
if(!match[v] || dfs(match[v]))
{
match[v] = u;
return true;
}
}
}
return false;
}

void init()
{
tot = 0;
memset(head,0,sizeof(head));
memset(to,0,sizeof(to));
memset(nxt,0,sizeof(nxt));
memset(match,0,sizeof(match));
}

double maxt = 0;

bool check(double T)
{
init();
int d = (T - t1) / (t1 + t2) + 1;
for(int i = 1;i <= n;i ++)
{
for(int j = 0;j < d;j ++)
{
double now = t1 + j * (t1 + t2);
for(int k = 1;k <= m;k ++)
{
if(now + t[i][k] <= T)
{
build(i + j * n,d * n + k);
build(d * n + k,i + j * n);
}
}
}
}
int ans = 0;
for(int i = 1;i <= d * n + m;i ++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)) ans ++;
}
//  printf("%d\n",ans);
return ans / 2 == m;
}

double div()
{
double l = t1,r = INF;
for(int i = 1;i <= 40;i ++)
{
double mid = (l + r) / 2;
if(check(mid)) r = mid;
else l = mid;
}
return r;
}

int x[SZ],y[SZ];

double calc(int x1,int y1,int x2,int y2)
{
double a = x1 - x2;
double b = y1 - y2;
return sqrt(a * a + b * b);
}
int main()
{
double v;
scanf("%d%d%lf%lf%lf",&n,&m,&t1,&t2,&v);
t1 /= 60;
for(int i = 1;i <= m;i ++)
{
scanf("%d%d",&x[i],&y[i]);
}
for(int i = 1;i <= n;i ++)
{
int xx,yy;
scanf("%d%d",&xx,&yy);
for(int j = 1;j <= m;j ++)
{
t[i][j] = calc(x[j],y[j],xx,yy) / v;
}
}
/*  for(int i = 1;i <= n;i ++)
{
for(int j = 1;j <= m;j ++)
printf("%lf ",t[i][j]);
puts("");
}   */
//  check(91.5);
printf("%.6lf\n",div());
return 0;
}


bzoj的数据好像比较强…匈牙利过不了……

然后敲了个网络流还是过不了…

认真规划了一下数组大小和memset次数,可算过了…这方面从来没在意过的我QAQ

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;

const double INF = 30000;
const int SZ = 500010;

int n,m;
double t1,t2;

double t[233][233];

int head[SZ],nxt[SZ],tot = 1,s,e;

struct edge{
int t,d;
}l[SZ];

void build(int f,int t,int d)
{
l[++ tot].t = t;
l[tot].d = d;
nxt[tot] = head[f];
head[f] = tot;
}

void insert(int f,int t,int d)
{
build(f,t,d); build(t,f,0);
}

queue<int> q;

int deep[SZ];

bool bfs()
{
memset(deep,0,sizeof(deep));
while(q.size()) q.pop();
deep[s] = 1;
q.push(s);
while(q.size())
{
int f = q.front(); q.pop();
for(int i = head[f];i;i = nxt[i])
{
int v = l[i].t;
if(!deep[v] && l[i].d)
{
deep[v] = deep[f] + 1,q.push(v);
//      if(v == e) return true;
}
}
}
if(deep[e]) return true;
return false;
}

int dfs(int u,int flow)
{
if(u == e || flow == 0) return flow;
int rest = flow;
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(deep[v] == deep[u] + 1 && l[i].d)
{
int f = dfs(v,min(rest,l[i].d));
if(f > 0)
{
rest -= f;
l[i].d -= f;
l[i ^ 1].d += f;
if(!rest) break;
}
else deep[v] = 0;
}
}
if(flow - rest == 0) deep[u] = 0;
return flow - rest;
}

int dinic()
{
int ans = 0;
while(bfs())
{
int tmp = dfs(s,INF);
if(tmp == 0) break;
ans += tmp;
}
return ans;
}

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

bool check(double T)
{
init();
int d = (T - t1) / (t1 + t2) + 1;
for(int i = 1;i <= n;i ++)
{
for(int j = 0;j < d;j ++)
{
double now = t1 + j * (t1 + t2);
for(int k = 1;k <= m;k ++)
{
if(now + t[i][k] <= T)
{
insert(i + j * n,d * n + k,1);
}
}
}
}
s = 0; e = d * n + m + 1;
for(int i = 1;i <= d * n;i ++)
insert(s,i,1);
for(int i = d * n + 1;i <= d * n + m;i ++)
insert(i,e,1);
return dinic() == m;
}

double div()
{
double l = t1,r = INF;
for(int i = 1;i <= 40;i ++)
{
double mid = (l + r) / 2;
if(check(mid)) r = mid;
else l = mid;
}
return r;
}

int x[SZ],y[SZ];

double calc(int x1,int y1,int x2,int y2)
{
double a = x1 - x2;
double b = y1 - y2;
return sqrt(a * a + b * b);
}
int main()
{
double v;
scanf("%d%d%lf%lf%lf",&n,&m,&t1,&t2,&v);
t1 /= 60;
for(int i = 1;i <= m;i ++)
{
scanf("%d%d",&x[i],&y[i]);
}
for(int i = 1;i <= n;i ++)
{
int xx,yy;
scanf("%d%d",&xx,&yy);
for(int j = 1;j <= m;j ++)
{
t[i][j] = calc(x[j],y[j],xx,yy) / v;
}
}
printf("%.6lf\n",div());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: