[DP 匈牙利 最小链覆盖] BZOJ 2044 三维导弹拦截 & 计蒜客 271 拦截导弹

19 篇文章 0 订阅

第一问就是偏序最长链 按一维排序然后DP即可

第二问是个最小链覆盖 那么转化为二分图 n-最大匹配


BZOJ上一个匈牙利就过了


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

struct abcd{
  int x,y,z;
  void read(){
    ::read(x); ::read(y); ::read(z);
  }
  bool operator < (const abcd &B) const{
    return x<B.x && y<B.y && z<B.z;
  }
};
bool cmp(abcd A,abcd B){
  return A.x<B.x;
}

const int N=1005;

int n; abcd a[N];
int f[N];

int vst[N],girl[N];

inline bool dfs(int u){
  for (int v=1;v<=n;v++)
    if (a[u]<a[v] && !vst[v]){
      vst[v]=1;
      if (!girl[v] || dfs(girl[v])){
	girl[v]=u;
	return 1;
      }
    }
  return 0;
}

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n);
  for (int i=1;i<=n;i++) a[i].read();
  sort(a+1,a+n+1,cmp);
  f[1]=1; int ans=0;
  for (int i=2;i<=n;i++){
    f[i]=1;
    for (int j=1;j<i;j++)
      if (a[j]<a[i])
	f[i]=max(f[i],f[j]+1);
    ans=max(ans,f[i]);
  }
  printf("%d\n",ans);
  ans=n;
  for (int i=1;i<=n;i++){
    cl(vst);
    if (dfs(i)) ans--;
  }
  printf("%d\n",ans);
  return 0;
}

计蒜客上就算dinic也不过

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

#define V G[p].v  
  
namespace DINIC{  
  const int N=2005;  
  const int M=2000005;  
  struct edge{  
    int u,v,f,next;  
  }G[M<<1];  
  int head[N],inum=1;  
  inline void add(int u,int v,int f,int p){  
    G[p].u=u; G[p].v=v; G[p].f=f; G[p].next=head[u]; head[u]=p;  
  }  
  inline void link(int u,int v,int f){  
    add(u,v,f,++inum); add(v,u,0,++inum);  
  }  
  inline void clear(){  
    cl(head); inum=1;  
  }  
  int S,T;  
  int Q[N],l,r;  
  int dis[N];  
  inline bool bfs(){  
    memset(dis,-1,sizeof(dis)); dis[S]=1;  
    l=r=-1; Q[++r]=S;  
    while (l<r){  
      int u=Q[++l];  
      for (int p=head[u];p;p=G[p].next)  
    if (G[p].f && dis[V]==-1){  
      dis[V]=dis[u]+1,Q[++r]=V;  
      if (V==T) return 1;  
    }  
    }  
    return 0;  
  }  
  int cur[N];  
  inline int dfs(int u,int flow){  
    if (u==T) return flow;  
    int used=0,now;  
    for (int p=cur[u];p;p=G[p].next){  
      cur[u]=p;  
      if (G[p].f && dis[V]==dis[u]+1){  
    now=dfs(V,min(G[p].f,flow-used));  
    G[p].f-=now; G[p^1].f+=now;  
    used+=now; if (flow==used) break;  
      }  
    }  
    if (!used) dis[u]=-1;  
    return used;  
  }  
  inline int Dinic(){  
    int ret=0;  
    while (bfs()) memcpy(cur,head,sizeof(head)),ret+=dfs(S,1<<30);  
    return ret;  
  }  
}  

struct abcd{
  int x,y,z;
  void read(){
    ::read(x); ::read(y); ::read(z);
  }
  bool operator < (const abcd &B) const{
    return x<B.x && y<B.y && z<B.z;
  }
};
bool cmp(abcd A,abcd B){
  return A.x<B.x;
}

const int N=1005;

int n; abcd a[N];
int f[N];

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n);
  for (int i=1;i<=n;i++) a[i].read();
  sort(a+1,a+n+1,cmp);
  f[1]=1; int ans=0;
  for (int i=2;i<=n;i++){
    f[i]=1;
    for (int j=1;j<i;j++)
      if (a[j]<a[i])
	f[i]=max(f[i],f[j]+1);
    ans=max(ans,f[i]);
  }
  printf("%d\n",ans);
  ans=n;
  using namespace DINIC;
  S=n+n+1; T=n+n+2;
  for (int i=1;i<=n;i++)
    link(S,i,1),link(n+i,T,1);
  for (int i=1;i<=n;i++)
    for (int j=1;j<i;j++)
      if (a[j]<a[i])
	link(j,n+i,1<<30);
  ans-=Dinic();
  printf("%d\n",ans);
  return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值