【bzoj 2044】三维导弹拦截(网络流)(拓扑排序)

来源:互联网 发布:软件问题报告模板 编辑:程序博客网 时间:2024/05/29 18:01

Description
一场战争正在A国与B国之间如火如荼的展开。 B国凭借其强大的经济实力开发出了无数的远程攻击导弹,B国的领导人希望,通过这些导弹直接毁灭A国的指挥部,从而取得战斗的胜利!当然,A国人民不会允许这样的事情发生,所以这个世界上还存在拦截导弹。 现在,你是一名A国负责导弹拦截的高级助理。 B国的导弹有效的形成了三维立体打击,我们可以将这些导弹的位置抽象三维中间的点(大小忽略),为了简单起见,我们只考虑一个瞬时的状态,即他们静止的状态。 拦截导弹设计非常精良,可以精准的引爆对方导弹而不需要自身损失,但是A国面临的一个技术难题是,这些导弹只懂得直线上升。精确的说,这里的直线上升指xyz三维坐标单调上升。 给所有的B国导弹按照1至N标号,一枚拦截导弹可以打击的对象可以用一个xyz严格单调上升的序列来表示,例如: B国导弹位置:(0, 0, 0) (1, 1, 0) (1, 1, 1), (2, 2, 2) 一个合法的打击序列为:{1, 3, 4} 一个不合法的打击序列为{1, 2, 4} A国领导人将一份导弹位置的清单交给你,并且向你提出了两个最简单不过的问题(假装它最简单吧): 1.一枚拦截导弹最多可以摧毁多少B国的导弹? 2.最少使用多少拦截导弹才能摧毁B国的所有导弹? 不管是为了个人荣誉还是国家容易,更多的是为了饭碗,你,都应该好好的把这个问题解决掉!

Input
第一行一个整数N给出B国导弹的数目。 接下来N行每行三个非负整数Xi, Yi, Zi给出一个导弹的位置,你可以假定任意两个导弹不会出现在同一位置。

Output
第一行输出一个整数P,表示一枚拦截导弹之多能够摧毁的导弹数。 第二行输出一个整数Q,表示至少需要的拦截导弹数目。

Sample Input
4
0 0 0
1 1 0
1 1 1
2 2 2

Sample Output
3
2

解题思路

拓扑排序+最小路径覆盖
代码:

#include<cstdio>  #include<algorithm>  #include<cmath>  #include<iostream>  #include<cstring>  #include<string>  #include<cstdlib>  #include<queue> using namespace std; struct ldx {     int x,y,z; }s[1005]; queue <int> q; int hed[1005],nex[1000005],lb[1000005],ru[1000005]; int pa[1005]; int n,ans=0,lo=0; void add(int x,int y) {     lo++;     nex[lo]=hed[x];     hed[x]=lo;     lb[lo]=y; } int had[2005],nax[2000005],lab[2000005],cap[2000005],dep[2005]; int loo=-1,si=2002,t=2003,mx=2147483640; void add1(int x,int y,int num) {     loo++;     nax[loo]=had[x];     had[x]=loo;     lab[loo]=y;     cap[loo]=num; } int dfs(int x,int num)  {      if(x==t || num==0) return num;      int c=0;      for(int i=had[x];i!=-1;i=nax[i])      if(dep[lab[i]]==dep[x]+1 && cap[i])      {          int f=dfs(lab[i],min(num,cap[i]));          c+=f;          num-=f;          cap[i]-=f;          cap[i^1]+=f;          if(num==0) break;      }      if(c==0) dep[x]=-1;     return c;  }  bool bfs()  {      memset(dep,0,sizeof(dep));      queue <int> qi;      qi.push(si);      dep[si]=1;      while(!qi.empty())      {          int x=qi.front();          qi.pop();          for(int i=had[x];i!=-1;i=nax[i])          if(!dep[lab[i]] && cap[i])          {             dep[lab[i]]=dep[x]+1;              qi.push(lab[i]);             }      }      return dep[t];  }  int dinic_()  {      int c=0;      while(bfs()) c+=dfs(si,mx);        return c;  }  int main() {     memset(had,-1,sizeof(had));     scanf("%d",&n);       for(int i=1;i<=n;i++) scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].z);     for(int i=1;i<=n;i++)      for(int j=1;j<=n;j++)       if(s[j].x>s[i].x && s[j].y>s[i].y && s[j].z>s[i].z)         {add(i,j);ru[j]++;}     for(int i=1;i<=n;i++)      if(ru[i]==0) {pa[i]=1;q.push(i);}     while(!q.empty())     {         int x=q.front();q.pop();                 for(int i=hed[x];i!=0;i=nex[i])           {              pa[lb[i]]=max(pa[lb[i]],pa[x]+1);ru[lb[i]]--;              if(ru[lb[i]]==0) q.push(lb[i]);           }       }       for(int i=1;i<=n;i++) ans=max(ans,pa[i]);     printf("%d\n",ans);     for(int i=1;i<=n;i++)      for(int j=1;j<=n;j++)       if(s[j].x>s[i].x && s[j].y>s[i].y && s[j].z>s[i].z)         {add1(i,j+1000,1);add1(j+1000,i,0);}     for(int i=1;i<=n;i++)              {         add1(si,i,1);add1(i,si,0);         add1(i+1000,t,1);add1(t,i+1000,0);       }     printf("%d",n-dinic_());       return 0; }
原创粉丝点击