[BZOJ] 2044: 三维导弹拦截

本文介绍了一种使用二维树状数组处理特定类型算法问题的方法,并通过构建有向无环图(DAG)来解决最小不可重链覆盖问题,详细展示了从输入处理到算法实现的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

排序去掉一维,剩下两维可以直接\(O(n^2)\)做,也可以用二维树状数组(但是不方便建边),解决第一问
第二问,按转移顺序连边,建出DAG,求最小不可重链覆盖即可

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>

using namespace std;

inline int rd(){
  int ret=0,f=1;char c;
  while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
  while(isdigit(c))ret=ret*10+c-'0',c=getchar();
  return ret*f;
}
#define space() putchar(' ')
#define nextline() putchar('\n')
void pot(int x){if(!x)return;pot(x/10);putchar('0'+x%10);}
void out(int x){if(!x)putchar('0');if(x<0)putchar('-'),x=-x;pot(x);}

const int MAXN = 2005;
const int INF = 1<<30;

int n;
struct Node{
    int x,y,z;
    Node(int a=0,int b=0,int c=0){x=a;y=b;z=c;}
    bool operator <(const Node &rhs)const{
        return x<rhs.x; 
    }
}node[MAXN];

int f[MAXN];
int ans1,ans2;

int nex[MAXN*MAXN],to[MAXN*MAXN],fl[MAXN*MAXN];
int head[MAXN],ecnt=1;
inline void adds(int x,int y,int f){
    nex[++ecnt]=head[x];to[ecnt]=y;
    fl[ecnt]=f;head[x]=ecnt;
}
inline void add(int x,int y,int f){
    adds(x,y,f);adds(y,x,0);    
}

int dep[MAXN];
queue<int> Q;
bool bfs(int s,int t){
    memset(dep,0,sizeof(dep));
    Q.push(s);dep[s]=1;
    while(!Q.empty()){
        int top=Q.front();Q.pop();  
        for(int i=head[top];i;i=nex[i]){
            int v=to[i];
            if(dep[v]||fl[i]==0) continue;
            dep[v]=dep[top]+1;
            Q.push(v);  
        }
    }
    return dep[t];
}
int cur[MAXN];
int dfs(int x,int flow,int t){
    if(x==t) return flow;
    int tmp,used=0;
    for(int &i=cur[x];i;i=nex[i]){
        int v=to[i];
        if(dep[v]!=dep[x]+1)continue;
        tmp=dfs(v,min(flow-used,fl[i]),t);
        used+=tmp;fl[i]-=tmp;fl[i^1]+=tmp;
        if(used==flow) return flow; 
    }
    if(!used) dep[x]=-1;
    return used;
}
int dinic(int s,int t){
    int ret=0;
    while(bfs(s,t)){
        memcpy(cur,head,sizeof(head));
        ret+=dfs(s,INF,t);  
    }
    return ret;
}
int main(){
    n=rd();
    int S=n+n+1,T=n+n+2;
    int x,y,z;
    for(int i=1;i<=n;i++){
        x=rd();y=rd();z=rd();
        node[i]=Node(x,y,z);
    }
    sort(node+1,node+1+n);
    for(int i=1;i<=n;i++){
        f[i]=1;
        add(S,i,1);add(i+n,T,1);
        for(int j=1;j<i;j++){
            if(node[j].x==node[i].x||node[j].y>=node[i].y||node[j].z>=node[i].z)continue;
            f[i]=max(f[i],f[j]+1);
            add(j,i+n,1);
        }
        ans1=max(ans1,f[i]);
    }
    ans2=n-dinic(S,T);
    out(ans1);nextline();
    out(ans2);
    return 0;
}

转载于:https://www.cnblogs.com/ghostcai/p/9867029.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值