解法一:
我们把所有人两辆之间的竞争力sum求出来,那么我们要求的就是sum - 每个队之间的内部竞争力;
那么为了使结果最大,我们应该使两个队内部之间的竞争力之和最小;
初始时,所有人都没有分队,依次考虑每一个人,要么把他安排在一队,要么放在二队,之和计算内部之间的竞争力并且向下 搜 索
这个做法能过,但是条件有点苛刻,只能打一个擦边球,只要少一个剪枝就tle;
①:当前结果已经大于已知结果,return;
②:其中一队的人数大于n。return
③:每次计算竞争力的时候只计算到st
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,a[30][30];
int f[30];
int d1[30],cnt1=0,cnt2=0,d2[30];
ll ans=0,sum=0;
void dfs(int st,ll s1,ll s2){
// cout<<st<<" "<<cnt1<<" "<<cnt2<<"pl \n";
if(s1+s2>=ans)return;
if(st>n*2){
// cout<<"fds";
ans=min(ans,s1+s2);
return;
}
if(cnt1>n||cnt2>n)return;
ll ss1=0,ss2=0;
for(int i=0;i<st;i++){
if(f[i]==1)ss1+=a[st][i];
if(f[i]==2)ss2+=a[st][i];
}
cnt1++;
f[st]=1;
dfs(st+1,s1+ss1,s2);
cnt1--;
cnt2++;
f[st]=2;
dfs(st+1,s1,s2+ss2);
cnt2--;
f[st]=0;
return;
}
int main(){
scanf("%d",&n);
for( int i=0;i<n*2;i++){
for(int j=0;j<n*2;j++){
scanf("%d",a[i]+j);
if(i<j)sum+=a[i][j];
}
}
for(int i=0;i<2*n;i++)f[i]=0;
ans=sum;
dfs(0,0,0);
printf("%lld\n",sum-ans);
return 0;
}
解法二:
思路和上面其实差不多,这次我们默认开始时所有人就处于同一个队,之和考虑每一个人,尝试把他划分到另一队,
不可以(或者说不能得到更优的结果)的话就保留在原队,这次我们需要更新的是两队之间的竞争力最大值。
那么当我们尝试把一个人从原来的队转移到另外一个队时,会队结果产生什么影响呢?
假设他(第x个人)对对其他人所产生的影响是总和是s[x], 已经转移了cnt个人,记录在在d[]数组中,
①:他原来对现在对队伍产生的影响会消失
ll nw
for(int i=0;i<cnt;i++){
nw+=a[x][d[i]];
}
②:他现在转移过来以后,会对原来的队伍产生影响
ll nw=s[x];
for(int i=0;i<cnt;i++){
nw-=a[x][d[i]];
}
那对总得到结果的影响值就是:
ll nw=s[x];
for(int i=0;i<cnt;i++){
nw-=a[x][d[i]]*2;
}
这个转移其实自己动手画一画,计算一下就很清楚了;
这个做法剪枝其实就没那么重要了,瞎搞就能过!!!!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,a[30][30],d[30],cnt=0;
ll sum,ans,s[30];
void dfs(int x,ll su){
if(cnt==n){
ans=max(ans,su);
return;
}
if(x>n*2)return;
if(n*2-x<n-cnt)return;
ll nw=s[x];
for(int i=0;i<cnt;i++){
nw-=a[x][d[i]]*2;
}
d[cnt++]=x;
dfs(x+1,su+nw);
cnt--;
dfs(x+1,su);
}
int main(){
scanf("%d",&n);
for(int i=0;i<n*2;i++){
for(int j=0;j<n*2;j++){
scanf("%d",a[i]+j);
s[i]+=a[i][j];
}
}
dfs(0,0);
printf("%lld",ans);
return 0;
}