サマースクールキャンプオフ以上の2019頭の牛(第2フィールド)F(検索)

質問の意味:

(2 * N \)\個人は、任意の2つの間の量を有する\(V_のIJを{} \) それが今すべき(2 * n個\)\ 2つのサイズに個人\(\ N-)を設定。合計値の大きさは以下のように定義される任意の二つの値が同じ人と右のキャンプではありません。あなたは合計最大値は、合計値の最大値を見つけるように、セットを分割する方法を尋ねます。

ソリューション:

今は二組あるため、\(A \)、\ (Bの\)ので、私たちは、2つの別々のコレクションを議論することを検討してください。以来\(A \) \ (B \) 同じ数の合計の、私たちは、コレクション列挙場合(A \)\を明らか次に、選択の数、集合\(B \)番号を選択するだけで必要になります同定しました。私たちは、列挙考える\(\)状態の集合を選択するので、私たちがすることができます(\ mathcal {O}(\ \ binom {2 * n}が{N})\) Aさんのすべての時間の複雑さを状態が列挙します。アップデート後、私たちはすぐに答えを検討している場合。

我々は唯一の列挙考えるので\(A \)状態の集合、と始まりを\(A \)の状態の集合である(1 \)\、次のプロセスが選択しなければなりません\(B \)をコレクションに特定の数に追加されました\(\)のコレクションでは、今、私たちは、元の望むことを前提としてい\(B \)セット\(a_iを\)を添加した\(\)のコレクションを。その後、明らかに、私たちはする必要があります(a_iを\)\と、元の\(\)を削除した貢献のすべての小さな集まり、今の増加\(B \)コレクションの時点で\(a_iを\)貢献。したがって、この時点で、我々は直接使用することができます\(\ mathcal {O}( \ n)を) 時間複雑答えが更新されます。

したがって、全体的な時間計算量は、\(\ mathcal {O}(\ Binom {2} * {N-N-N- *})\) 時間の複雑さが、それはまだ限界に非常に近いので、我々はいくつかの必要な剪定は、それを高速に実行可能追加することができます。

コード:

#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;
}

おすすめ

転載: www.cnblogs.com/Chen-Jr/p/11221929.html