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

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。

敌国的导弹形成了立体打击,每个导弹可以抽象成一个三维空间中的点(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());
}
时间: 2024-10-22 23:21:13

SSL 2732_导弹拦截_dp+最小路径覆盖的相关文章

bzoj 2044 三维导弹拦截——DAG最小路径覆盖(二分图)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2044 还以为是CDQ.发现自己不会三维以上的-- 第一问可以n^2.然后是求最长不下降子序列吗?dilworth好像不能用吧. 那就是能从自己转移到哪些状态就从自己向哪些状态连边,然后就是最小路径覆盖了.用二分图的 n-最大匹配 . 注意:没有位置的限制所以可以先按 x 排序! #include<iostream> #include<cstdio> #include<c

bzoj 2044 三维导弹拦截 —— 最小路径覆盖

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2044 第一问暴力 n^2 即可: 注意这道题对位置没要求!所以先按第一维排序一下即可: 然后拆入点和出点,求一个最小路径覆盖即可. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const

hiho 第118周 网络流四&#183;最小路径覆盖

描述 国庆期间正是旅游和游玩的高峰期. 小Hi和小Ho的学习小组为了研究课题,决定趁此机会派出若干个调查团去沿途查看一下H市内各个景点的游客情况. H市一共有N个旅游景点(编号1..N),由M条单向游览路线连接.在一个景点游览完后,可以顺着游览线路前往下一个景点. 为了避免游客重复游览同一个景点,游览线路保证是没有环路的. 每一个调查团可以从任意一个景点出发,沿着计划好的游览线路依次调查,到达终点后再返回.每个景点只会有一个调查团经过,不会重复调查. 举个例子: 上图中一共派出了3个调查团: 1

hdu3861 强连通+最小路径覆盖

题意:有 n 个点,m 条边的有向图,需要将这些点分成多个块,要求:如果两点之间有路径能够互相到达,那么这两个点必须分在同一块:在同一块内的任意两点相互之间至少要有一条路径到达,即 u 到达 v 或 v 到达 u:每个点都只能存在于单独一个块内.问最少需要划分多少块. 首先,对于如果两点之间能够相互到达则必须在同一块,其实也就是在同一个强连通分量中的点必须在同一块中,所以首先就是强连通缩点.然后在同一块内的任意两点之间要有一条路,那么其实就是对于一块内的强连通分量,至少要有一条路径贯穿所有分量.

COGS728. [网络流24题] 最小路径覆盖问题

算法实现题8-3 最小路径覆盖问题(习题8-13) ´问题描述: 给定有向图G=(V,E).设P是G的一个简单路(顶点不相交)的集合.如果V中每个顶点恰好在P的一条路上,则称P是G的一个路径覆盖.P中路径可以从V的任何一个顶点开始,长度也是任意的,特别地,可以为0.G的最小路径覆盖是G的所含路径条数最少的路径覆盖.设计一个有效算法求一个有向无环图G的最小路径覆盖. 提示: 设V={1,2,...  ,n},构造网络G1=(V1,E1)如下: 每条边的容量均为1.求网络G1的(x0,y0)最大流.

【最小路径覆盖】BZOJ2150-部落战争

[题目大意] 给出一张图,'*'表示不能走的障碍.已知每只军队可以按照r*c的方向行军,且军队与军队之间路径不能交叉.问占据全部'.'最少要多少支军队? [思路] 首先注意题意中有说“军队只能往下走”,弄清楚方向. 从某点往它能走的四个点走一趟,连边.最小路径覆盖=总数-二分图最大匹配. 哦耶!老了,连匈牙利的板子都敲错orzzzzzz 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=55; 4 int m,n

有向无环图(DAG)的最小路径覆盖

DAG的最小路径覆盖 定义:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点. 最小路径覆盖分为最小不相交路径覆盖和最小可相交路径覆盖. 最小不相交路径覆盖:每一条路径经过的顶点各不相同.如图,其最小路径覆盖数为3.即1->3>4,2,5. 最小可相交路径覆盖:每一条路径经过的顶点可以相同.如果其最小路径覆盖数为2.即1->3->4,2->3>5. 特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0. DAG的最小不相交路径覆盖 算法:把原图的每个点

hdu 3861 The King’s Problem (强连通+最小路径覆盖)

The King's Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1637    Accepted Submission(s): 600 Problem Description In the Kingdom of Silence, the king has a new problem. There are N cit

POJ 3020 Antenna Placement ,二分图的最小路径覆盖

题目大意: 一个矩形中,有N个城市'*',现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市. 问至少放置多少个基站才能使得所有的城市都覆盖无线? 无向二分图的最小路径覆盖 = 顶点数 –  最大二分匹配数/2 路径覆盖就是在图中找一些路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联: #include<cstdio> #include<cstring> #include<vector> #include<algor