【2019牛客暑期多校训练营(第二场)- F】Partition problem(dfs,均摊时间优化)

题干:

链接:https://ac.nowcoder.com/acm/contest/882/F
来源:牛客网
 

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 ∑i=12N∑j=i+12N(vij if i-th person is not in the same team as j-th person else 0)\sum_{i=1}^{2N} \sum_{j=i+1}^{2N} (v_{ij} \text{ if i-th person is not in the same team as j-th person else } 0 )∑i=12N​∑j=i+12N​(vij​ 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 vijv_{ij}vij​ is the j-th value of the i-th line which indicates the competitive value of person i and person j.

* 1≤N≤141 \leq N \leq 141≤N≤14
* 0≤vij≤1090 \leq v_{ij} \leq 10^{9}0≤vij​≤109
* vij=vjiv_{ij} = v_{ji}vij​=vji​

输出描述:

Output one line containing an integer representing the maximum possible total competitive value.

示例1

输入

复制

1
0 3
3 0

输出

复制

3

题目大意:

时限4秒。

将2*n个人分到两个team,每个team必须恰好有n个人,如果i,j两个人位于不同的team,那么收益增加 a[i][j],求分配的最大收益

第一行输入n

第二行输入一个(2*n)*(2*n)的矩阵。

【2019牛客暑期多校训练营(第二场)- F】Partition problem(dfs,均摊时间优化)

求最大收益。

解题报告:

  最暴力的方法是C(2*n,n)枚举,但是最后对于每一种情况算答案的时候需要n^2处理,这样总复杂度就是O( C(2*n,n) * n^2 ),在n=14的情况下是会T的。想办法优化掉一个N。(  C(28,14) = 40116600)

可以这么转化一下问题,其实可以看成本来2*n个人都在一个team中,现在要拽其中一些人去另一个team,所以每当拽一个人去另一个team的时候,就减去对应的贡献。这样的好处就是,把最后统计需要On^2的时间均摊到每一次的dfs中线性完成,这样总复杂度就是O( C(2*n,n) * n ),可以接受。这题时限4秒。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
const ll mod = 1e9 + 7;
ll ma;
vector<int> v;
int n;
ll a[33][33],d[33];//d[i]代表i和其他所有点连边的权值和。
void dfs(ll x,ll ans) {
	if(v.size()==n) {
		ma = max(ma,ans); return ;
	}
	if(v.size()>n || x>=2*n) return ;
	ll now=d[x];
	for(auto s:v) now -= a[x][s]*2;
	//选 
	v.push_back(x);
	dfs(x+1,ans+now);
	//不选 
	v.pop_back();
	dfs(x+1,ans);
}
int main() 
{
	scanf("%d",&n);
	for(int i=0; i<2*n; i++)
		for(int j=0; j<2*n; j++) {
			scanf("%lld",&a[i][j]);
			d[i]+=a[i][j];
		}
	dfs(0,0);
	cout << ma <<endl;
	return 0 ; 
}
上一篇:Redis 集群


下一篇:基于SQL和pandas的欧洲足球数据分析【附图详解】