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=12Nj=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.

* 1N141≤N≤14
* 0vij1090≤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個人分為兩部分,每一個人與另外一半的每一個人貢獻一個權值,求貢獻和的最大值。
思路:
暴力搜索,最壞的復雜度是C(2*14,14),也就是差不多4e7,如果你確定某一個人在第一部分,還可以將復雜度除而2
關於算貢獻,你可以選擇14*14的復雜度,但是肯定會T
在搜索的時候,如果n=5,那么第一次選在第一部分的人就是 1 2 3 4 5.
第二次選在第一部分的人就是 1 2 3 4 6,可以發現只有一個數字不同。
分析一下,其實在整個搜索的過程中,也會出現很多這樣只差一個的數組。
於是,我們可以記錄上一個狀態,通過上個狀態算出當前狀態,這樣可以減小很多算貢獻的復雜度。
就這樣,我的代碼跑了3700ms之后卡過去了。
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
int n;
ll mp[30][30];
bool vis[30];
ll MIN;
int v1[30];
int v2[30];
int prev1[30];
int prev2[30];
ll prenum = 0;
ll C[35][35];
//C[n][m]就是C(n,m)
int tot;
void init(int N) {
    for (int i = 0; i < N; i ++) {
        C[i][0] = C[i][i] = 1;
        for (int j = 1; j < i; j ++) {
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
            C[i][j] %= mod;
        }
    }
}


void dfs(int x, int deep) {//必須>=x開始,已經選了num個人
    if (deep == n) {
        tot--;
        if(tot<0){return;}
        int cnt1 = 0;
        int cnt2 = 0;
        for (int i = 1; i <= 2 * n; i++) {
            if (vis[i]) v1[++cnt1] = i;
            else v2[++cnt2] = i;
        }
        ll num = prenum;
        int pos = 1;
        for (int i = 1; i <= n; i++) {
            if (v1[i] != prev1[i]) {
                pos = i;
                break;
            }
        }
        for (int i = pos; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                num -= mp[prev1[i]][prev2[j]];
                num -= mp[v1[i]][prev1[j]];
            }
            for (int j = 1; j <= n; j++) {
                num += mp[v1[i]][v2[j]];
                num += mp[v1[j]][prev1[i]];
            }
        }
        MIN = max(MIN, num);
        for (int i = 1; i <= n; i++) {
            prev1[i] = v1[i];
            prev2[i] = v2[i];
            prenum = num;
        }
        return ;
    }
    for (int i = x + 1; i <= 2 * n; i++) {
        vis[i] = 1;
        dfs(i, deep + 1);
        if(tot<0){return;}
        vis[i] = 0;
    }
}
int main() {
    MIN = -1;
    init(30);
    scanf("%d", &n);
    tot=C[2*n][n];
    tot/=2;
    for (int i = 1; i <= 2 * n; i++) {
        for (int j = 1; j <= 2 * n; j++) {
            scanf("%lld", &mp[i][j]);
        }
    }
    dfs(0, 0);
    printf("%lld\n", MIN);
    return 0;
}
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM