老师为即将毕业的同学们准备了一场舞会,有 2 N 2N 2N个同学会参加这场舞会,他们会被分成 N N N对跳舞,每个人有一个编号,如果编号为 i i i的同学和编号为 j j j的同学配对,那么这一对的满意度是 A i , j ( i < j ) A_{i,j}(i<j) Ai,j(i<j),我们规定这个舞会的满意度为每一队的满意度的异或和,也就是说,当同学们分成 N N N组后,第 i i i对同学的满意度为 A i A_i Ai,那么舞会的满意度为 A 1 ⊕ A 2 ⊕ . . . A N A1⊕A2⊕...AN A1⊕A2⊕...AN
请你求出本场舞会满意度的最大值
输入描述
第一行给出一个数 N N N,有 2 N 2N 2N个人参加舞会
接下来给出一个矩阵表示 i i i和 j j j配对时的满意度
A 1 , 2 , A 1 , 3 , . . . A 1 , 2 N A_{1,2},A_{1,3},...A_{1,2N} A1,2,A1,3,...A1,2N
A 2 , 3 , . . . A 2 , 2 N A_{2,3},...A_{2,2N} A2,3,...A2,2N
… … …
A 2 N − 1 , 2 N A_{2N−1,2N} A2N−1,2N
其中 1 ≤ N ≤ 8 , 0 ≤ A i , j ≤ 2 30 1≤N≤8,0≤A_{i,j}≤2^{30} 1≤N≤8,0≤Ai,j≤230
输出描述
输出本场舞会满意度的最大值
样例输入
2
4 0 1
5 3
2
样例输出
6
样例解释
如果 { 1 , 2 } , { 3 , 4 } , a n s = A 1 , 2 ⊕ A 3 , 4 = 4 ⊕ 2 = 6 \{1,2\},\{3,4\},ans=A_{1,2}⊕A_{3,4}=4⊕2=6 {1,2},{3,4},ans=A1,2⊕A3,4=4⊕2=6
如果 { 1 , 3 } , { 2 , 4 } , a n s = A 1 , 3 ⊕ A 2 , 4 = 0 ⊕ 3 = 3 \{1,3\},\{2,4\},ans=A_{1,3}⊕A_{2,4}=0⊕3=3 {1,3},{2,4},ans=A1,3⊕A2,4=0⊕3=3
如果 { 1 , 4 } , { 2 , 3 } , a n s = A 1 , 4 ⊕ A 2 , 3 = 1 ⊕ 5 = 4 \{1,4\},\{2,3\},ans=A_{1,4}⊕A_{2,3}=1⊕5=4 {1,4},{2,3},ans=A1,4⊕A2,3=1⊕5=4
最后答案为 m a x ( 6 , 3 , 4 ) = 6 max(6,3,4)=6 max(6,3,4)=6
解题思路
因为数据 N ≤ 8 N\le8 N≤8,所以直接 D F S + DFS+ DFS+剪枝就可以。
问题可能在于如何 D F S DFS DFS:
写一个 D F S DFS DFS需要定义四个部分(并不一定都需要):状态部分(函数声明),停止条件,主体部分,返回后操作。
我们从简单到复杂逐个定义。
(1)结束条件:配对数到达 n n n;
(2)返回后操作:将已配对的两个人取消标记;
(3)状态部分:状态部分为已配对数、舞会满意度;
(4)主体部分:首先利用一个循环找出第一个未配对的人,然后再用一个循环去为他搭配所有可能。
void dfs(int couple, int confid) {//状态if (couple == n + 1) {//结束条件ans = max(ans, confid);return;}//函数主体int i, j;for (i = 1; i <= 2 * n; i++) {if (!vis[i]) {for (j = i + 1; j <= 2 * n; j++) {if (!vis[j]) {vis[i] = vis[j] = true;dfs(couple + 1, confid ^ relation[i][j]);vis[i] = vis[j] = false;//返回后操作}}}}
}
如何降低时间复杂度:
(1)依靠遍历顺序: 1 , 2 1,2 1,2和 2 , 1 2,1 2,1算一种情况,所以只考虑前者(递增序),依靠遍历查找的顺序来实现;
(2)依靠 D F S DFS DFS序:我们在第一层配对 1 1 1和 3 3 3,在第二层配对 2 2 2和 4 4 4这种情况与我们在第一层配对 2 2 2和 4 4 4和在第二层配对 1 1 1和 3 3 3二者是相同的。
优化之后的算法如下:
void dfs(int couple, int confid) {if (couple == n + 1) {ans = max(ans, confid);return;}int i, j;for (i = 1; i <= 2 * n; i++) {if (!vis[i]) break;//DFS序剪枝}for (j = i + 1; j <= 2 * n; j++) {//遍历顺序剪枝if (!vis[j]) {vis[i] = vis[j] = true;dfs(couple + 1, confid ^ relation[i][j]);vis[i] = vis[j] = false;}}
}
AC代码如下:
#include <iostream>
using namespace std;
const int max_n = 16;int relation[max_n + 1][max_n + 1], n, ans;
bool vis[max_n + 1];void dfs(int couple, int confid) {if (couple == n + 1) {ans = max(ans, confid);return;}int i, j;for (i = 1; i <= 2 * n; i++) {if (!vis[i]) break;}for (j = i + 1; j <= 2 * n; j++) {if (!vis[j]) {vis[i] = vis[j] = true;dfs(couple + 1, confid ^ relation[i][j]);vis[i] = vis[j] = false;}}
}int main() {cin >> n;for (int i = 1; i <= 2 * n; i++) {for (int j = i + 1; j <= 2 * n; j++) {cin >> relation[i][j];}}dfs(1, 0);cout << ans << endl;return 0;
}
(并没有什么奇妙的算法呢 q w q qwq qwq)