题目传送门: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;
}
:)等会还是会用二分图再做一遍的