20201017B组 T2 导弹拦截

9 篇文章 0 订阅

20201017B组 T2 导弹拦截

jzoj5354

题目大意

给出 n n n ( n ≤ 1000 ) (n\le 1000) (n1000)个三维坐标 x i , y i , z i x_i,y_i,z_i xi,yi,zi,求任意排列下的最长上升子序列和最小链覆盖

TJ

前一问显然用 O ( n 2 ) O(n^2) O(n2)DP暴力求,你想用 O ( n l o g n ) O(nlogn) O(nlogn)也是可以的

对于后一问,乍一看可以用

最小链覆盖等于最长反链

于是信誓旦旦的打了个最长不上升子序列,结果没过样例,才发现反链不是我想象中的那种东西。。。

然后考虑拆点,每有点 X − > Y X->Y X>Y就连接 A x A_x Ax B y B_y By,跑匈牙利算法,最小链覆盖就等于 n n n减去匹配数。

原因是每有一个匹配就相当于把两个原图上的点连了起来,没有连的时候每个点都是一条链,连一次就可以少去一条链,二分图匹配保证了每个点的初度和入度都小于2,所以一定是链。

其实也可以写最大流跑的,具体搜索:有向图的最小链覆盖

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
const int INF=1e9+7;
using namespace std;
const int N=1e3;
struct node{
	int x,y,z;
}a[N+10];
struct edge{
	int st,en,next;
}E[N*N];
int n,m,f[N+10],ans1,ans2,tot,last[N+10],g[N*2+10];
bool vis[N*2+10];
void add(int x,int y){
	E[++tot]=(edge){x,y,last[x]};
	last[x]=tot;
}
bool cmp(node a,node b){
	if(a.x!=b.x)return a.x<b.x;
	if(a.y!=b.y)return a.y<b.y;
	return a.z<b.z;
}
bool cmp2(node a,node b){
	if(a.x!=b.x)return a.x>b.x;
	if(a.y!=b.y)return a.y>b.y;
	return a.z>b.z;
}
bool dfs(int x){
	for(int p=last[x];p;p=E[p].next){
		int y=E[p].en;
		if(vis[y])continue;
		vis[y]=1;
		if(g[y]==-1 || dfs(g[y])){
			g[y]=x;
			return 1;
		}
	}
	return 0;
}
int solve(int n){
	int ret=0;
	memset(g,-1,sizeof(g));
	fo(i,1,n){
		memset(vis,0,sizeof(vis));
		ret+=dfs(i);
	}
	return n-ret;
}
int main(){
	freopen("missile.in","r",stdin);
	freopen("missile.out","w",stdout);
	scanf("%d",&n);
	fo(i,1,n){
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
	}
	sort(a+1,a+n+1,cmp);
	fo(i,1,n){
		f[i]=1;
		fo(j,1,i-1){
			if(a[j].x<a[i].x && a[j].y<a[i].y && a[j].z<a[i].z){
				f[i]=max(f[i],f[j]+1);
				add(i,j+n);
			}
		}
		ans1=max(ans1,f[i]);
	}
	ans2=solve(n);
	printf("%d\n%d\n",ans1,ans2);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值