洛谷1559 运动员最佳匹配问题 题解

题目传送门:https://www.luogu.org/problemnew/show/P1559

呜呜呜我终于自己想出怎么优化算法了。本来想练练二分图就看到这道题,这道题题意就是二分图求最大权匹配,然而只会求最大匹配的蒟蒻我并不会什么KM算法(等会看看好了),一看数据范围 (1≤n≤20),毫不犹豫进行搜索。以下为第一版代码(完全无优化的深搜):

#include
#include
int p[51][51]={0},q[51][51]={0},vis[101]={0},step[101]={0};
int max=-1,n;
int judge()
{
    int i,sum=0;
    for(i=1;i<=n;i++)
      sum+=p[i][step[i]]*q[step[i]][i];
    if(sum>max)
      max=sum;
    return 0;
}
int dfs(int i)
{
    int j;
    if(i==n+1)  {judge();return 0;}
    for(j=1;j<=n;j++)
      if(vis[j]==0)
        {
        vis[j]=1;
        step[i]=j;
        dfs(i+1);
        step[i]=0;
        vis[j]=0;
        }
    return 0;
}
int main()
{
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
        scanf("%d",&p[i][j]);
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
        scanf("%d",&q[i][j]);
    dfs(1);
    printf("%d",max);
    return 0;
}

TLE两个点,然后我尝试了把judge函数中sum的叠加放在dfs内然后直接在dfs函数里进行sum和max的判断但是毫无作用。沉思十分钟,我感受到了韩哥哥(woc这三个字加了划线像没加一样)搜索人民的伟大智慧,想起了国王游戏,国王游戏是利用左手*右手进行排序,那我们这里也可以利用这个思想。我们取男运动员x1,x2,女运动员y1,y2,假如我们使x1与y1配对,x2与y2配对,得到的价值就为p[x1][y1]*q[y1][x1]+p[x2][y2]*q[y2][x2],如果我们使x1与y2配对,x2与y1配对得到的价值为p[x1][y2]*q[y2][x1]+p[x2][y1]*q[y1][x2],那么我们利用贪心的思想,这里面我们只能取大的那个,弃掉小的那个,于是利用一个四维数组vis1来记录这一切,再加上升级版判断能否深搜的judge(不要看这个函数n级别他可以避免接下来复杂度爆炸的深搜),附上代码:

#include
#include
int p[51][51]={0},q[51][51]={0},vis[101]={0},vis1[21][21][21][21]={0},step[101]={0},match[101]={0};
int max=-1,n,sum=0;
int judge(int x,int y)
{
    int i;
    for(i=1;imax)
      max=sum;
    if(i==n+1)  return 0;
    for(j=1;j<=n;j++)
      if(vis[j]==0&&judge(i,j))
        {
        sum+=p[i][j]*q[j][i];
        vis[j]=1;
        match[i]=j;
        dfs(i+1);
        match[i]=0;
        sum-=p[i][j]*q[j][i];
        vis[j]=0;
        }
    return 0;
}
int main()
{
    int i,j,k,l;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
        scanf("%d",&p[i][j]);
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
        scanf("%d",&q[i][j]);
    for(i=1;i<=n;i++)
      for(j=1;j<=n;j++)
        for(k=1;k<=n;k++)
          if(k!=i)
            for(l=1;l<=n;l++)
              if(l!=j)
                {
                if(p[i][j]*q[j][i]+p[k][l]*q[l][k]>p[i][l]*q[l][i]+p[k][j]*q[j][k])
                   {vis1[i][l][k][j]=-1;vis1[k][j][i][l]=-1;}
                else {vis1[i][j][k][l]=-1;vis1[k][l][i][j]=-1;}
                }
    dfs(1);
    printf("%d",max);
    return 0;
}

:)等会还是会用二分图再做一遍的

你可能感兴趣的:(二分图)