2019牛客暑期多校训练营(第二场) F Partition problem 【DFS暴力搜索+优化】

题目描述

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 \sum_{i=1}^{2N}\sum_{j=i+1}^{2N}(v_i_j 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 v_i_j 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≤v_i_j≤109
* v_i_j=v_j_i

输出描述

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,也就是说最坏的情况是C_2_8^1^4,达到4e7左右,可以暴力搜索。大概思路就是利用DFS从2N个人中选N个人组成一队,剩下的人自成另一队。但是这里如果是每种情况搜索结束时才计算所有v的和,由于每次有n^2的复杂度,会超时。所以这里采用每种情况在搜索过程中就动态维护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;
}
发布了30 篇原创文章 · 获赞 5 · 访问量 900

猜你喜欢

转载自blog.csdn.net/qq_42840665/article/details/97132978