[NOI2003]智破连环阵

最近颓得很,这道题写了整整三天

先去看了一下楼天城和朱泽园两位神仙的论文

被各种骚操作吊打得怀疑人生

首先每枚炸弹炸毁的武器应该是一段连续的区间

那么我们可以把武器划分成$ans$段

对于每一段武器,都用一枚炸弹去炸毁

现在我们考虑怎么样求出最小的$ans$

直接搜索肯定超时,考虑剪枝优化

把每段武器看成一个点,每枚炸弹看成一个点

搜索的时候用二分图优化即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int m,n,k,ans,u[101],v[101],x[101],y[101],f[101],vis[101],step[101],ok[101][101],to[101][101];
inline bool check (int a,int b)
{ return (u[a]-x[b])*(u[a]-x[b])+(v[a]-y[b])*(v[a]-y[b])<=k*k; }
inline bool find (int x) {
for(register int i=1;i<=n;++i)
if(!vis[i]&&ok[i][x]) {
vis[i]=true;
if(!f[i]||find(f[i])) {
f[i]=x;
return true;
}
}
return false;
}
inline int read () {
char ch=getchar(); int num=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) num=(num<<3)+(num<<1)+(ch^'0'),ch=getchar();
return num;
}
inline void dfs (int now,int sum) {
if(ans<=sum+step[now]) return ;
if(now>m) { ans=sum; return ; }
int g[101]; memcpy(g,f,sizeof(g));
for(register int i=now;i<=m;++i) {
for(register int j=1;j<=n;++j)
if(check(j,i)&&to[j][now]>=i) ok[j][sum+1]=true;
memset(vis,false,sizeof(vis));
if(find(sum+1)) dfs(i+1,sum+1);
for(register int j=1;j<=n;++j)
if(check(j,i)&&to[j][now]>=i) ok[j][sum+1]=false;
memcpy(f,g,sizeof(f));
}
}
int main () {
m=read(),n=read(),k=read(); ans=n;
for(register int i=1;i<=m;++i) x[i]=read(),y[i]=read();
for(register int i=1;i<=n;++i) u[i]=read(),v[i]=read();
for(register int i=1;i<=n;++i)
for(register int j=m;j;--j)
if(check(i,j)) to[i][j]=max(j,to[i][j+1]);
for(register int i=1;i<=m;++i) step[i]=INF;
for(register int i=m;i;--i)
for(register int j=1;j<=n;++j)
if(check(j,i)) step[i]=min(step[i],step[to[j][i]+1]+1);
dfs(1,0); printf("%d\n",ans);
return 0;
}