蓝桥杯ADV-151算法提高花之战的解题思维。

对于70%的数据,直接用全排列枚举每个女生对应的人然后求解,取最大值,时间复杂度为O(n*n!),对于n

对于100%的数据,我们可以使用状态压缩的方法进行动态规划:

Dp[i][j]的意思是现在I女都参与进来了,占座学生的身份是J的最大系统。

状态j用二进制表示,第k位是1?意味着第k个学生已经被占用了。

比如j=3,二进制数是0000011,说明1和第二个学生已经被占用了。

对于初始状态:

dp[0][j]=0

传递方程为:

DP[I][j]= max(DP[I-1][k]+like[I][t])?

其中t是J中1的1的位置,k是J将第t位变成0的数字。找到所有t的一边取一个最大值然后+like[i][t],就是dp[i][j]?

答案是DP [n] [2 n-1]

时间复杂度应该是o (n * 2 n)

考虑到所有的I只与i-1相关,可以减少一维空间消耗。

对于n

最后,贴一个刚刚写好的新鲜代码:

#包含?& ltiostream & gt

#包含?& ltcstdio & gt

#包含?& ltcstring & gt

#包含?& lt算法& gt

#定义?MAXN?15

使用?命名空间?std

const?int?maxzt =(1 & lt;& lt13);?//最大状态数,

int?DP[maxzt];

int?像[MAXN][MAXN],n;

int?numberOfOne(int?num){?//num?二进制数1。

int?CNT = 0;

while(num){

CNT+=(num & amp;1);

num & gt& gt=1;

}

回归?cnt

}

int?lowbit(int?x){//num?只保留二进制中的最后1?比如:?num=20?二进制10100?回归?二进制100,也就是4。

回归?x & amp(-x);

}

int?posOfOne(int?num){?//num?二进制中最后1的位置如下:?num=18?二进制10010?回归?2

int?pos = 0;

while(num){

pos++;

如果(数字& amp1)

回归?pos

num & gt& gt=1;

}

回归?pos

}

作废?工作(int?x){

int?max status = 1 & lt;& ltn;

for(int?I = 0;我& ltmaxstatusi++){

int?nowstatus=i,t = number of one(now status);

如果(t!=x)?继续;?//x女有x 1。如果没有,继续寻找下一个号码。

while(t - ){

int?pos = low bit(now status);

dp[i]=max(dp[i],DP[I-pos]+like[x][posOfOne(pos)]);

now status-= pos;

}

}

}

int?main(){

scanf("%d ",& ampn);

for(int?I = 1;我& lt= n;i++)

for(int?j = 1;j & lt= n;j++)

scanf("%d ",& amp像[I][j]);

memset(dp,0,sizeof(DP));

for(int?I = 1;我& lt= n;i++)

工作(一);

printf("%d\n ",DP[(1 & lt;& ltn)-1]);

回归?0;

}