牛客多校二(F)

题目:Partition problem

解法一:

      我们把所有人两辆之间的竞争力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;
}
发布了70 篇原创文章 · 获赞 5 · 访问量 7188

猜你喜欢

转载自blog.csdn.net/xiaonanxinyi/article/details/96714484