2019牛客暑期多校訓練營(第二場)----F-Partition problem

首先發出題目鏈接:
鏈接:https://ac.nowcoder.com/acm/contest/882/F
來源:牛客網
涉及:優先深度搜索

點擊這裏回到2019牛客暑期多校訓練營解題—目錄貼


題目如下:
在這裏插入圖片描述
在這裏插入圖片描述
2n2n個人分成兩個人數爲nn的隊伍,相當於2n2n個球放進兩個相同的盒子裏,且每個盒子有n個球,一共有C2nnC_{2n}^n中方法。

對於每一種分法,一個隊伍裏面的任何一個人與另一個隊伍的所有人之間都有一個競爭值。

於是,暴力算總競爭值需要O(n2)O(n^2)的複雜度。

所以總複雜度爲n2C2nnn^2C_{2n}^n很明顯會超時,所以我們需要預處理一下


我們只要確定一個隊伍,另一個隊伍自然也被確定了。

在開始輸入競爭值時,可以用一個數組來存一個人對於其他所有人競爭值的總和(all數組)

for(i=1;i<=2*n;i++){
	all[i]=0;
	for(j=1;j<=2*n;j++){
		scanf("%d",&v[i][j]);
		all[i]+=v[i][j];
	}
}

用vector容器表示一個隊伍,剛開始這個隊伍是空的(表示所有人都在另一個隊伍),同理開始的競爭值爲0。

vector<int> team;

遍歷每一個人,假設此時遍歷到第x個人,嘗試兩種情況

1.將第x個人加入隊伍team,那麼此時的競爭值會增加,競爭值先增加all[x]如果隊伍team本來就有人,此時第i個人與隊伍team內的人之間是沒有競爭力的,此時要減去多增加的競爭力,然後將這個人放入隊伍。

	mans+=all[x];
	for(int i=0;i<team.size();i++)	mans-=2*v[x][team[i]];
	team.push_back(x);
	dfs(x+1,mans);

注意要減去兩倍的競爭力,因爲競爭力是互相產生的。

2.或者不將第i個人放入隊伍team,直接考慮第x+1個人。


還要注意限制條件,隊伍team中的人數不能大於n個;同時最多隻能考慮到第2n個人。
還有一個注意的地方,見下面dfs代碼中,team.pop_back();的語句。

dfs代碼:

void dfs(int x,ll mans){//x表示現在考慮第x個人,mans存當前分法的總競爭力值
	if(team.size()==n){//如果team中有n個人,表示這是一種新的分法,然後比較當前總競爭力mans和當前最小總競爭力ans哪個小。
		ans=max(ans,mans);//比較
		return;//注意返回
	}	
	if(x>2*n)	return;	//最多隻能考慮到第2*n個人
	dfs(x+1,mans);//第一種情況,不考慮第x個人,直接考慮第x+1個人
	//下面是第二種情況:考慮將第x個人放入team中
	mans+=all[x];
	for(int i=0;i<team.size();i++)	mans-=2*v[x][team[i]];
	team.push_back(x);
	dfs(x+1,mans);
	team.pop_back();//注意在返回之前,要將第x個人移出隊伍,因爲返回代表着重新考慮第x-1個人。
	return;
}

代碼如下:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
int n;//題目所給變量
ll all[30];//all[i]表示第i個人與其他所有人之間競爭力總和
ll v[30][30];//題目所給變量
vector<int> team;//當前隊伍
ll ans=0;//答案
void dfs(int x,ll mans){//x表示現在考慮第x個人,mans存當前分法的總競爭力值
	if(team.size()==n){//如果team中有n個人,表示這是一種新的分法,然後比較當前總競爭力mans和當前最小總競爭力ans哪個小。
		ans=max(ans,mans);//比較
		return;//注意返回
	}	
	if(x>2*n)	return;	//最多隻能考慮到第2*n個人
	dfs(x+1,mans);//第一種情況,不考慮第x個人,直接考慮第x+1個人
	//下面是第二種情況:考慮將第x個人放入team中
	mans+=all[x];//先將all[x]值加上
	for(int i=0;i<team.size();i++)	mans-=2*v[x][team[i]];//然後依次減去同一隊伍中之間的競爭力
	team.push_back(x);//將當前第x個人放入隊伍
	dfs(x+1,mans);
	team.pop_back();//注意在返回之前,要將第x個人移出隊伍,因爲返回代表着重新考慮第x-1個人。
	return;
}
int main(){
	scanf("%d",&n);
	int i,j;
	for(i=1;i<=2*n;i++){
		all[i]=0;
		for(j=1;j<=2*n;j++){
			scanf("%d",&v[i][j]);
			all[i]+=v[i][j];
		}
	}
	dfs(1,0ll);
	return !printf("%lld",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章