Title description
Given 2N people, you need to assign each of them into either red team or white team such that each team consists of exactly N people and the total competitive value is maximized.
Total competitive value is the summation of competitive value of each pair of people in different team.
The equivalent equation is ( if i-th person is not in the same team as j-th person else 0)
Enter description
The first line of input contains an integers N.
Following 2N lines each contains 2N space-separated integers is the j-th value of the i-th line which indicates the competitive value of person i and person j.
* 1≤N≤14
* 0≤≤109
* =
Output description
Output one line containing an integer representing the maximum possible total competitive value.
Example input
1
0 3
3 0
Sample output
3
The main idea:
There are 2N individuals, to be divided into two teams, each team N people. There is a v value between everyone in one team and everyone in the other team, and the maximum sum of v values that can be obtained after being divided into two teams is required (the specific summation method is given by the formula in the question) .
analysis:
Looking at the data of the topic, the maximum N is 14, which means that the worst case is that it can reach violent search when it reaches about 4e7. The general idea is to use DFS to select N individuals from 2N individuals to form a team, and the rest to form another team. But if this is to calculate all the v until the end of each case and the search because every time complexity, time out. So here we use each case to dynamically maintain the sum of v in the search process, so that each case has only n complexity.
See the code for specific explanation.
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
ll val[30][30];
ll maxx=0;
int vis[30];//0表示在本队,1表示在另一队
int n;
void dfs(int index,int cnt,ll tmpsum){
if(index>2*n) return;//下标超过2N,返回
if(2*n-index+cnt<n) return;//剩下的人数已经不够选出N个人,返回
if(cnt>=n){
//在这里计算和值会超时
// ll tmp=0;
// rep(i,1,2*n){
// rep(j,i+1,2*n){
// if(vis[i]!=vis[j]) tmp+=val[i][j];
// }
// }
maxx=max(maxx,tmpsum);
// cout<<"t"<<tmpsum<<endl;
return;
}
ll nxtsum=tmpsum;
//选择当前下标的人去"1"队
vis[index]=1;
rep(i,1,2*n){
if(vis[i]!=1){
nxtsum+=val[i][index];//当前下标的人和"0"队所有的人的v值加入和值
}
else{
nxtsum-=val[i][index];//扣除当前下标的人和"1"队所有人的v值(在之前过多的加入了)
}
}
dfs(index+1,cnt+1,nxtsum);
//选择当前下表的人留在"0"队
vis[index]=0;
dfs(index+1,cnt,tmpsum);
}
int main(){
scanf("%d",&n);
rep(i,1,2*n){
rep(j,1,2*n){
scanf("%lld",&val[i][j]);
}
}
memset(vis,0,sizeof(vis));
dfs(1,0,0);
cout<<maxx<<endl;
return 0;
}