题目描述
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)
输入描述
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 one line containing an integer representing the maximum possible total competitive value.
示例输入
1
0 3
3 0
示例输出
3
题目大意:
有2N个人,要分成两队,每队N个人。一个队中的每个人和另一队中的每个人之间都有一个v值, 要求出分成两队后所能得到的最大的v值之和(具体的和求法由题中公式给出)。
分析:
看题目的数据,N最大是14,也就是说最坏的情况是,达到4e7左右,可以暴力搜索。大概思路就是利用DFS从2N个人中选N个人组成一队,剩下的人自成另一队。但是这里如果是每种情况搜索结束时才计算所有v的和,由于每次有的复杂度,会超时。所以这里采用每种情况在搜索过程中就动态维护v的和值,这样每种情况只有n的复杂度。
具体解释见代码。
#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;
}