【bzoj 2044】三维导弹拦截(拓扑排序+最小路径覆盖)

传送门biu~
第一个问题,对于导弹a严格小于导弹b,我们可以连一条a->b的边,对于整个图来说,因为边表示的关系是大小关系,所以这个图一定是个拓扑图,只要拓扑排序递推求最长链就可以了。
第二个问题,同样像上一个问题那样连边,求最小路径覆盖。

#include <bits/stdc++.h>
#define S 0
#define T 2001
#define INF 1000000000
using namespace std;
int n;
//task1:
struct dd{
    int x,y,z;
    bool operator<(const dd &r){return (x<r.x && y<r.y && z<r.z);}
}a[1005];
int head1[1005],in1[1005],nex1[1000005],to1[1000005],tp1=0;
queue<int>q;int len[1005];
inline void add(int x,int y){
    nex1[++tp1]=head1[x];
    head1[x]=tp1;
    to1[tp1]=y;
    ++in1[y];
}
inline int topo(){
    int ans=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head1[x];i;i=nex1[i]){
            len[to1[i]]=max(len[to1[i]],len[x]+1);
            if(!--in1[to1[i]])  q.push(to1[i]);
        }
        ans=max(ans,len[x]);
    }
    return ans;
}
inline void solve1(){
    for(int i=1;i<=n;++i)       
        for(int j=1;j<=n;++j)
            if(a[i]<a[j])   add(i,j);
    for(int i=1;i<=n;++i)   if(!in1[i]) q.push(i),len[i]=1;
    printf("%d\n",topo());
}
//task2:
int head2[2005],nex2[2000005],to2[2000005],cap2[2000005],tp2=1;
int dep[2005],fir[2005];
inline void add2(int x,int y){
    nex2[++tp2]=head2[x];
    head2[x]=tp2;
    to2[tp2]=y;
    cap2[tp2]=1;
    nex2[++tp2]=head2[y];
    head2[y]=tp2;
    to2[tp2]=x;
    cap2[tp2]=0;
}
int dfs(int x,int now)
{
    if(!now || x==T)    return now;
    int c=0;
    for(int &i=fir[x];i;i=nex2[i])
    {
        if(cap2[i] && dep[to2[i]]==dep[x]+1)
        {
            int f=dfs(to2[i],min(now,cap2[i]));
            c+=f;
            now-=f;
            cap2[i]-=f;
            cap2[i^1]+=f;
            if(!now)        break;
        }
    }
    return c;
}
inline bool bfs()
{
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    queue<int>q;
    q.push(S);
    while(!q.empty())
    {
        int x=q.front();   q.pop();
        for(int i=head2[x];i;i=nex2[i])
        {
            if(cap2[i]&&!dep[to2[i]])
            {
                dep[to2[i]]=dep[x]+1;
                q.push(to2[i]);
            }
        }
    }
    return dep[T];
}
inline int Dinic(){
    int c=0;
    while(bfs()){
        for(int i=1;i<=2*n;++i)     fir[i]=head2[i];
        fir[S]=head2[S];            fir[T]=head2[T];
        c+=dfs(S,INF);
    }
    return c;
}
inline void solve2(){
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            if(a[i]<a[j])       add2(i,n+j);
    for(int i=1;i<=n;++i)       add2(S,i);
    for(int i=n+1;i<=2*n;++i)   add2(i,T);
    printf("%d",n-Dinic());
}
inline void init(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)   scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
}

int main(){
    init();
    solve1();
    solve2();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zP1nG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值