poj 3565 uva 1411 Ants KM算法求最小权

  由于涉及到实数,一定,一定不能直接等于,一定,一定加一个误差<0.00001,坑死了……

  有两种事物,不难想到用二分图。这里涉及到一个有趣的问题,这个二分图的完美匹配的最小权值和就是答案。为啥呢?因为如果有四个点,a,b,c,d Abcd交叉,acbd不交叉,那么acbd的长度和一定小于abcd的长度和,可以画一个图很容易就证出来。所以,如果所有的边都不交叉,又因为有解,那么最小的权值和就是解了。附图一枚,自己画的,比较简陋,凑活着看吧……

poj 3565 uva 1411 Ants KM算法求最小权

  KM算法求最佳完美匹配最小权值和,可以直接把所有的权值转成负值,在求最大权值和,但是这种方法我觉得有些不对劲,但是不知道在哪里= =,上网一查,才发现这种方法只能用于xy数量相同的时候,正统做法应该是用一个很大的数减去每个权值,再求最大权值和。PS:我用的是取反的方法……

 

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#define N 110

struct sss

{

    int x,y;

}white[N],black[N];

int n,vx[N],vy[N],fa[N];

double w[N][N],px[N],py[N],str[N];

double dis(int i,int j)

{

    return sqrt((double)(black[i].x-white[j].x)*(black[i].x-white[j].x)+(double)(black[i].y-white[j].y)*(black[i].y-white[j].y));

}

int find(int now)

{

    int i,j,k;

    if (now==0)

      return 1;

    vx[now]=1;

    for (i=1;i<=n;i++)

    {

      if (!vy[i]&&fabs(px[now]+py[i]-w[now][i])<0.00001)

      {

          vy[i]=1;

          if (fa[i]==0||find(fa[i]))

          {

              fa[i]=now;

              return 1;

          }

      }

      else

        if (str[i]>px[now]+py[i]-w[now][i])

          str[i]=px[now]+py[i]-w[now][i];

    }

    return 0;

}

void KM()

{

    int i,j,k,x,y,z;

    double na;

    memset(fa,0,sizeof(fa));

    for (i=1;i<=n;i++)

    {

        memset(str,0x7f,sizeof(str));

        while (1)

        {

            memset(vx,0,sizeof(vx));

            memset(vy,0,sizeof(vy));

            if (find(i))

              break;

            na=0x7f;

            for (j=1;j<=n;j++)

              if (!vy[j]&&na>str[j])

                na=str[j];

            for (j=1;j<=n;j++)

            {

                if (vx[j])

                  px[j]-=na;

                if (vy[j])

                  py[j]+=na;

                else

                  str[j]-=na;

            }

        }

    }

}

int main()

{

    int i,j,k,x,y,z;

    z=0;

    while(scanf("%d",&n)!=EOF)

    {

        if (z)

          printf("\n");

        else

          z=1;

        for (i=1;i<=n;i++)

          px[i]=-100000;

        memset(py,0,sizeof(py));

        for (i=1;i<=n;i++)

          scanf("%d%d",&white[i].x,&white[i].y);

        for (i=1;i<=n;i++)

          scanf("%d%d",&black[i].x,&black[i].y);

        for (i=1;i<=n;i++)

          for (j=1;j<=n;j++) 

          {

              w[i][j]=-dis(i,j);

              if (px[i]<w[i][j])

                px[i]=w[i][j];

          }

        KM();

        for (i=1;i<=n;i++)

          printf("%d\n",fa[i]);

    }

}

 

 

你可能感兴趣的:(ant)