2019牛客暑期多校训练营(第二场)F.Partition problem(搜索剪枝)

链接: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 ∑2Ni=1∑2Nj=i+1(vij 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 vijvij is the j-th value of the i-th line which indicates the competitive value of person i and person j.

* 1≤N≤141≤N≤14
* 0≤vij≤1090≤vij≤109
* vij=vjivij=vji

输出描述:

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

示例1

输入

复制

1
0 3
3 0

输出

复制

3

题目大意:给你一个N,现在有2*N个人,你要做的就是把这2*N个人分成两队一队N个人,下面会给一个表,也就是每个人对其他人的作用,你要做的就是保证两个队伍作用的最大值,队伍作用的最大值是每个人对另一支队伍的作用的和

思路:这个题目当时做的时候没有做出来,后来看了有人过了的代码才做出来的,发现好像没有那么难的,

首先要明白每一个人一定会属于一个队伍,而且队伍名字的互换并不会产生任何影响,那么不妨假设1号在A队(这里我们把队伍分为AB两队)

然后就是暴力的搜索,对于我查过的区间就不要再去查,对于新进的编号,如果他本身就属于队伍A,那么你的队伍A的作用就要减去新进编号对之前A队伍的作用,加上新进编号对队伍B的作用,在A队数量满足题意时拉出来判断就好,最后做一个剪枝,详情见代码吧,有一定注释的

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=30;
ll a[maxn][maxn];
ll ans=0;
int n;
/*
mit 我们用二进制的位来表示2*n个人,第i位为1则i在A中
num 队伍A的人数
pre 我们是从前往后暴力查找所以就不用管前面的,
ans2 当前的答案
*/
void DFS(int mit,int num,int pre,ll ans2)
{
    //cout<<"num:"<<num<<endl;
    if(num==n/2)
    {
        ans=max(ans,ans2);
        return ;
    }
    if(n/2<pre-num) return ;
    for(int i=pre+1;i<=n;i++)//往后找
    {
        ll t=ans2;
        for(int j=1;j<=n;j++)//判断一下新进编号对于其他编号的作用
        {
            if((mit>>j)&1)
                t-=a[i][j];
            else
                t+=a[i][j];
        }
        DFS(mit|(1<<i),num+1,i,t);
    }
}
int main()
{
    scanf("%d",&n);
    n*=2;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%lld",&a[i][j]);
    ll temp=0;
    for(int i=1;i<=n;i++)//我们假设1号已经在A队中
        temp+=a[1][i];
    //cout<<n<<" "<<temp<<endl;
    DFS(2,1,1,temp);
    printf("%lld\n",ans);
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值