感觉和之前百度之星那题是差不多套路吧,都是搜索套上一个二分图优化
很容易知道,每个炸弹都是炸掉连续的一段
然后你就搜索一下哪些段
然后二分图判定一下
注意要边搜索边判定,这样是一个强大的可行性剪枝,然后就可以跑过去了
其实在分段的时候也有技巧,就是肯定是在每个炸弹端点的时候分,但是我比较懒,没有加,反正也过了
因为这题数据随机
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=105;
int m,n,k;//武器 炸弹 攻击范围
struct qq
{
int x,y;
}a[N],b[N];
int dis (qq a,qq b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int ans;
bool ok[N][N];
bool s[N][N];//能不能炸到
int tt[N][N];//这个点如果是true的话下一个是什么
int f[N];//这个炸弹配对了谁
bool vis[N];
bool find (int x)
{
for (int u=1;u<=n;u++)
if (ok[u][x]&&vis[u])
{
vis[u]=false;
if (f[u]==-1||find(f[u]))
{
f[u]=x;
return true;
}
}
return false;
}
int dist[N];
void dfs (int y,int z)//划分到第几个点 划分了多少段
{
if (z+dist[y]>=ans) return ;
if (y>m)
{
ans=z;
return ;
}
int ff[N];
for (int i=y;i<=m;i++)//这一段划在哪里
{
for (int j=1;j<=n;j++)
{
ff[j]=f[j];
if (s[j][y]==true&&tt[j][y]>=i)
ok[j][z+1]=true;
}
memset(vis,true,sizeof(vis));
if (find(z+1)) dfs(i+1,z+1);
for (int j=1;j<=n;j++)
{
f[j]=ff[j];
if (s[j][y]==true&&tt[j][y]>=i)
ok[j][z+1]=false;
}
}
}
int main()
{
scanf("%d%d%d",&m,&n,&k);
for (int u=1;u<=m;u++) scanf("%d%d",&a[u].x,&a[u].y);
for (int u=1;u<=n;u++) scanf("%d%d",&b[u].x,&b[u].y);
memset(s,false,sizeof(s));
for (int u=1;u<=n;u++)
for (int i=1;i<=m;i++)
if (dis(b[u],a[i])<=k*k)
s[u][i]=true;
for (int u=1;u<=n;u++)
for (int i=m;i>=1;i--)
{
if (s[u][i]==false) continue;
tt[u][i]=max(i,tt[u][i+1]);
}
memset(dist,127,sizeof(dist));
dist[m+1]=0;
for (int u=m;u>=1;u--)
{
for (int i=1;i<=n;i++)
{
if (s[i][u]==false) continue;
dist[u]=min(dist[u],dist[tt[i][u]+1]+1);
}
}
memset(f,-1,sizeof(f));
memset(ok,false,sizeof(ok));
ans=n;
dfs(1,0);
printf("%d\n",ans);
return 0;
}