More than 2019 cattle off summer school camp (second field) F (Search)

Meaning of the questions:

There \ (2 * n \) individuals, has a weight between any two \ (ij of V_ {} \) . It should now \ (2 * n \) individuals into two size \ (n-\) set. The size of the total value is defined as: any two values are not the same person and the right camp. You ask how to divide the set, so that the total maximum value, find the maximum of the total value.

answer:

Because now there are two sets \ (A \) , \ (B \) , so we consider will discuss two separate collections. Since \ (A \) , \ (B \) of the total number of the same, so if we enumerate the collection (A \) \ number of selected, then obviously the set \ (B \) which will be the only need to select the number confirmed. We consider enumeration only \ (A \) select the set of states, so we can \ (\ mathcal {O} ( \ binom {2 * n} {n}) \) time complexity of all of the A's state enumerated. After the update if we consider the answers quickly.

Because we only consider the enumeration \ (A \) set of states, and the beginning \ (A \) set of states is \ (1 \) , then the process following must be to select \ (B \) in the collection was added to a certain number of \ (a \) in the collection, now we assume that we want the original \ (B \) set \ (a_i \) was added \ (a \) collection. Then obviously, we just need to \ (a_i \) original with (A \) \ all the little collection of contribution deleted, and now increase in \ (B \) with the point of collection (a_i \) \ contribution. So at this time, we can directly use \ (\ mathcal {O} ( n) \) time complexity answer is updated.

Thus, the overall time complexity is \ (\ mathcal {O} (\ Binom {2} * {n-n-n-*}) \) . The time complexity but it is still very close to the limit, so we can add some necessary pruning makes it run faster.

Code:

#include <bits/stdc++.h>
#define maxn 40
using namespace std;
typedef unsigned long long ll;
ll res=0;
int n,v[maxn][maxn];
//sta是状压了一个2*n位的二进制位,代表当前A集合选取的状态,若当前位为1则代表选1
//cnt代表A选取了的状态
//pre代表当前已经选了前pre个点
//cost代表贡献
void dfs(int sta,int cnt,int pre,ll cost){
    if(cnt==n/2){ //两边集合相同,更新答案
        res=max(res,cost);
        return;
    }
    if(n-pre-1+cnt<n/2) return; //剪枝,如果发现A集合的数量大于B集合的数量,直接终止
    for(int i=pre+1;i<n;i++){ //枚举当前需要将第i个点加到A集合中
        ll cur=cost;
        for(int j=0;j<n;j++){
            if(sta&(1<<j)) cur-=v[i][j]; //如果在原来的状态下第j位是处在A集合中,则直接减去第i个点在第j个点的贡献
            else cur+=v[i][j]; //如果在原来的状态下第j位是处在B集合中,则直接加上第i个点在第j个点的贡献
        }
        dfs(sta|(1<<i),cnt+1,i,cur);
    }
}
int main()
{
    scanf("%d",&n);
    n<<=1;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            scanf("%d",&v[i][j]);
    for(int i=0;i<n;i++){
        res+=v[0][i];
    }
    dfs(1,1,0,res);
    printf("%llu\n",res);
    return 0;
}

Guess you like

Origin www.cnblogs.com/Chen-Jr/p/11221929.html