【JZOJ1156】【GDKOI2004】使命的召唤(二分图匹配)

Problem

  给定n(≤200)个机枪阵地,阵地i有两个整数xi,yi(0<=xi,yi<=30000)代表其坐标。给出m(≤30000)条连接两个阵地的路。一个敢死队员可以空降到任一个阵地上,炸掉一个阵地后,可以从当前阵地出发沿着路到达下一个x坐标比当前阵地大的阵地。
  注意:每个阵地都必须被摧毁,且每个阵地只能被经过一次。

Solution

  • 超级裸的二分图匹配。。。居然没想出来。。。
  • 把每个阵地拆成两个点。这样,就有两排点,每排n个点。
  • 如果阵地x能走到阵地y,则从左边的x连向右边的y。比如假如1能走到2,2能走到3;我们就从左边的1连向右边的2,左边的2连向右边的3。

  • 然后,直接上匈牙利算法/最大流求出最大匹配,ans即为n-匹配数。
  • 因为一开始每个阵地都要放敢死队员;但是如果我们用左边和1和右边的2匹配了,炸完阵地1的敢死队员就可以跑去炸阵地2,于是可以省一个人。
  • 因此,每匹配一组,就可以省一个人。

  • 时间复杂度: O ( n m ) o r       O ( )

Code

#include <cstdio>
#include <cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;

const int N=201;
int i,n,x[N],y,m,p,q,ans,res[N];
bool a[N][N],bz[N];

inline void link(int x,int y){a[x][y]=1;}

bool find(int x)
{
    int y;
    fo(y,1,n)
        if( a[x][y] && !bz[y] )
        {
            bz[y]=1;
            if( !res[y] || find(res[y]) )
            {
                res[y]=x;
                return 1;
            }
        }
    return 0;
}

int main()
{
    scanf("%d",&n);
    fo(i,1,n) scanf("%d%d",&x[i],&y);
    scanf("%d",&m);
    fo(i,1,m)
    {
        scanf("%d%d",&p,&q);
        if(x[p]<x[q]) link(p,q);
        else    
        if(x[p]>x[q]) link(q,p);
    }

    fo(i,1,n)
    {
        memset(bz,0,sizeof bz);
        ans+=find(i);
    }

    printf("%d",n-ans);
} 

猜你喜欢

转载自blog.csdn.net/qq_36551189/article/details/81081959