【JZOJ5354】【NOIP2017提高A組模擬9.9】導彈攔截【網路流】【DP】
阿新 • • 發佈:2019-01-05
題目大意:
題目連結:https://jzoj.net/senior/#main/show/5354
某國為了防禦敵國的導彈襲擊,發展出一種導彈攔截系統。
敵國的導彈形成了立體打擊,每個導彈可以抽象成一個三維空間中的點(x; y; z)。攔截系統發射的炮彈也很好地應對了這種情況,每一發炮彈也可以視為一個三維空間中的點。
但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達三維空間中任意的點,但是以後每一發炮彈到達點的座標(x; y; z) 的三個座標值都必須大於前一發炮彈的對應座標值。
某天,雷達捕捉到敵國的導彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈。
輸入導彈飛來的座標,計算這套系統最多能攔截多少導彈,如果要攔截所有導彈最少要配備多少套這種導彈攔截系統。注意: 所有導彈都是同時飛來的。
思路:
對於第一問,很明顯可以意
中任意一維為關鍵字排序後
動態規劃求出。方程為
對於第二問,可以用網路流求。
如果
可以從
轉移而來(
),那麼就從點
向點
連一條邊。那麼,這個圖就是一個有向無環圖。我們要求這個圖中的最小點覆蓋。
那麼考慮拆點,把每一個點
拆成
和
。若
可以從
轉移而來,那麼久從
向
連邊。源點
連向所有點
,匯點
由所有點
連過來。然後跑一邊最大流,最小點覆蓋即
。
程式碼:
#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\n%d\n",ans+1,n-maxflow);
return 0;
}