bzoj 4622: [NOI 2003] 智破连环阵【dfs+匈牙利算法】

一个炸弹炸一个区间的武器,想到二分图匹配
但是直接dfs断点显然不行,预处理出dis[i]为i到m的至多值来最优性剪枝,并且标记ok[i][j]为炸弹i可以炸到j武器,mx[i][j]为i炸弹从j武器开始最远能炸到哪,c[i][j]为i炸弹炸到1时候有j这个右端点
然后dfs+二分图匹配即可

#include<iostream>
#include<cstdio>
using namespace std;
const int N=105;
int m,n,k,lk[N],v[N],ti,mx[N][N],dis[N],ans=1e9;
bool ok[N][N],c[N][N],f[N][N];
struct qwe
{
    int x,y;
}a[N],b[N];
bool zhao(int u)
{
    for(int i=1;i<=n;i++)
        if(v[i]!=ti&&f[u][i])
        {
            v[i]=ti;
            if(!lk[i]||zhao(lk[i]))
            {
                lk[i]=u;
                return 1;
            }
        }
    return 0;
}
void dfs(int w,int va)
{
    if(va+dis[w]>=ans)
        return;
    if(w>m)
    {
        ans=va;
        return;
    }
	int q[N],top;
    for(int i=m;i>=w;i--)
        if(c[w][i])
        {
            top=0;
            for(int j=1;j<=n;j++)
                if(mx[j][w]==i)
                    f[va+1][q[++top]=j]=1;
            ti++;
            if(zhao(va+1))
                dfs(i+1,va+1);
            for(int j=1;j<=top;j++)
            {
                f[va+1][q[j]]=0;
                if(lk[q[j]]==va+1)
                    lk[q[j]]=0;
            }
        }
}
int main()
{
    scanf("%d%d%d",&m,&n,&k);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&b[i].x,&b[i].y);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&a[i].x,&a[i].y);
    for(int j=m;j>=1;j--)
    {
        dis[j]=1e9;
        for(int i=1;i<=n;i++)
            if((a[i].x-b[j].x)*(a[i].x-b[j].x)+(a[i].y-b[j].y)*(a[i].y-b[j].y)<=k*k)
            {
                ok[i][j]=1;
                mx[i][j]=ok[i][j+1]?mx[i][j+1]:j;
                c[j][mx[i][j]]=1;
                dis[j]=min(dis[j],dis[mx[i][j]+1]+1);
            }
    }
    dfs(1,0);
    printf("%d\n",ans);
    return 0;
}
posted @ 2018-10-12 17:19  lokiii  阅读(130)  评论(0编辑  收藏  举报