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

题目描述 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;
}

你可能感兴趣的:(【bzoj3035】【codevs2490】导弹防御塔 二分+匈牙利 || 二分+dinic)