SSL 2732_导弹拦截_dp+最小路径覆盖

lzusa 发布于 2017-09-16 1 次阅读


题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
敌国的导弹形成了立体打击,每个导弹可以抽象成一个三维空间中的点(x; y; z)。拦截系统发射的炮弹也很好地应对了这种情况,每一发炮弹也可以视为一个三维空间中的点。
但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达三维空间中任意的点,但是以后每一发炮弹到达点的坐标(x; y; z) 的三个坐标值都必须大于前一发炮弹的对应坐标值。
某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹飞来的坐标,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。注意: 所有导弹都是同时飞来的


 

思路

orz人生导师jpwang

前一问一个dp,f[i]表示拦截第i个可以拦截最多拦截到的导弹

f[i] = 1

f[i] = max(f[j]+1) (1 <= j < i) 且受题目限制   来考虑第二问 我们可以将i拆点为 i, i', 对于两个导弹i,j,若从i可以打j,那么我们就连一条(i,j')的边 这样就变成了一个二分图,因为我们要将全部点都达到,所以就是求一个二分图的最小路径覆盖 = 点数 - 最大匹配 跑网络流或其他算法都可以


#include <stdio.h>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
#define max(x, y) (x) > (y) ? (x) : (y)
#define min(x, y) (x) < (y) ? (x) : (y)
#define INF 0x7f7f7f7f
#define fill(x, y) memset(x, y, sizeof(x))
struct edge
{
    int x, y, z;
}e[2000001];
struct arr
{
    int to, w, next;
}e1[2000001];
int n, f[10001], ls[20001], cur[20001], state[20001], S, E;
inline int read()
{
    int x=0,p=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-')p=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*p;
}
int cmp(edge a, edge b)
{
    return a.x < b.x ;
}
int maxE = 1;
int add(int x, int y, int w)
{
    e1[++maxE] = (arr) {y, w, ls[x]};
    ls[x] = maxE;
    e1[++maxE] = (arr) {x, 0, ls[y]};
    ls[y] = maxE;
}
int bfs(int S, int E)
{
    queue<int> t;
    fill(state, 0);
    t.push(S);
    state[S] = 1;
    while (!t.empty())
    {
        int now = t.front();
        t.pop();
        for (int i = ls[now]; i; i = e1[i].next)
        {
            if (e1[i].w > 0 && !state[e1[i].to])
            {
                state[e1[i].to] = state[now] + 1;
                t.push(e1[i].to);
                if (e1[i].to == E)
                    return true;
            }
        }
    }
    return false;
}
int find(int now, int mn)
{
    if (!mn || now == E)
        return mn;
    int ret = 0;
    for (int &i = cur[now]; i; i = e1[i].next)
        if (state[now] + 1 == state[e1[i].to] && e1[i].w > 0)
        {
            int d = find(e1[i].to, min(e1[i].w, mn - ret));
            e1[i].w -= d;
            e1[i^1].w += d;
            ret += d;
            if (ret == mn) break;
        }
    return ret;
}
int dinic()
{
    int ans = 0;
    while (bfs(S, E))
    {
        for (int i = S; i <= E; i++)
            cur[i] = ls[i];
        ans += find(S, INF);
    }
    return ans;
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        {
            e[i].x = read();
            e[i].y = read();
            e[i].z = read();
        }
    sort(e + 1, e + n + 1, cmp);
    for (int i = 1; i <= n; i++)
    {
        f[i] = 1;
        for (int j = 1; j < i; j++)
        {
            if (e[j].x < e[i].x && e[j].y < e[i].y && e[j].z < e[i].z)
                f[i] = max(f[i], f[j] + 1);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        ans = max(ans, f[i]);
    }
    printf("%d\n", ans);
    int l = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j < i; j++)
            if (e[j].x < e[i].x && e[j].y < e[i].y && e[j].z < e[i].z)
                add(j, i + n, 1);
    S = 0;
    E = n * 2 + 1;
    for (int i = 1; i <= n; i++)
    {
        add(S, i, 1);
        add(i + n, E, 1);
    }
    printf("%d", n - dinic());
}