• 【JZOJ5354】【NOIP2017提高A组模拟9.9】导弹拦截【网络流】【DP】


    题目大意:

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


    思路:

    对于第一问,很明显可以意x,y,zx,y,z中任意一维为关键字排序后O(n2)O(n^2)动态规划求出。方程为
    f[j]=max(f[j],f[i]+1)(xi<xj,yi<yj,zi<zj)f[j]=max(f[j],f[i]+1)(x_i<x_j,y_i<y_j,z_i<z_j)
    对于第二问,可以用网络流求。
    如果jj可以从ii转移而来(xi<xj,yi<yj,zi<zjx_i<x_j,y_i<y_j,z_i<z_j),那么就从点ii向点jj连一条边。那么,这个图就是一个有向无环图。我们要求这个图中的最小点覆盖。
    那么考虑拆点,把每一个点xx拆成xax_axbx_b。若jj可以从ii转移而来,那么久从iai_aibi_b连边。源点SS连向所有点ia(i1n)i_a(iin1sim n),汇点TT由所有点ib(i1n)i_b(iin1sim n)连过来。然后跑一边最大流,最小点覆盖即nmaxflown-maxflow


    代码:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    
    const int N=1010;
    const int Inf=2e9;
    int n,tot=1,ans,maxflow,S,T;
    int f[N],head[N*2],cur[N*2],dep[N*2];
    
    struct node
    {
    	int x,y,z;
    }a[N];
    
    struct edge
    {
    	int next,to,flow;
    }e[N*N];
    
    bool cmp(node x,node y)
    {
    	return x.z<y.z;
    }
    
    void add(int from,int to,int flow)
    {
    	e[++tot].to=to;
    	e[tot].flow=flow;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    bool bfs()  //分层
    {
        memset(dep,0x3f3f3f3f,sizeof(dep));
        memcpy(cur,head,sizeof(cur));  //当前弧优化
        dep[S]=0;
        queue<int> q;
        q.push(S);
        while (q.size())
        {
            int u=q.front();
            q.pop();
            for (int i=head[u];~i;i=e[i].next)
            {
                int v=e[i].to;
                if (dep[v]>dep[u]+1&&e[i].flow)  
                {
                    dep[v]=dep[u]+1;
                    q.push(v);
                }
            }
        }
        return dep[T]<0x3f3f3f3f;
    }
    
    int dfs(int u,int flow)
    {
        int low=0;
        if(u==T)
    	{
            maxflow+=flow;  //最大流
            return flow;
        }
        int used=0;
        for (int i=cur[u];~i;i=e[i].next)
    	{
            int v=e[i].to;
            cur[u]=i;  //当前弧
            if (e[i].flow&&dep[v]==dep[u]+1)
    		{
    			low=dfs(v,min(flow-used,e[i].flow));
    			if (low)
    			{
    				used+=low;
    	            e[i].flow-=low;
    	            e[i^1].flow+=low;
    	            if(used==flow) break;  //流满了就不能再流了
    			}
            }
        }
        return used;
    }
    
    void dinic()
    {
    	while (bfs())
    		dfs(S,Inf);
    }
    
    int main()
    {
    	freopen("missile.in","r",stdin);
    	//freopen("missile.out","w",stdout);
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    	sort(a+1,a+1+n,cmp);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    			if (a[i].x<a[j].x&&a[i].y<a[j].y&&a[i].z<a[j].z)
    			{
    				f[j]=max(f[j],f[i]+1);
    				ans=max(ans,f[j]);
    				add(i,j+n,1);  //连边
    				add(j+n,i,0);
    			}
    	S=n*2+1;
    	T=n*2+2;
    	for (int i=1;i<=n;i++)
    	{
    		add(S,i,1);
    		add(i,S,0);
    		add(i+n,T,1);
    		add(T,i+n,0);
    	}
    	dinic();
    	printf("%d
    %d
    ",ans+1,n-maxflow);
    	return 0;
    }
    
  • 相关阅读:
    技巧使用
    一些常用的安装包可选安装组件
    php ob_flush与flush的作用
    HTML5 localStorage本地存储
    php clearstatcache
    iconv
    Mysql数字类型转换函数
    POJ
    POJ
    POJ
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998420.html
Copyright © 2020-2023  润新知