【搜索】Partition problem

题目链接:传送门

题面:

 

 

【题意】

  给定2×n个人的相互竞争值,请把他们分到两个队伍里,如果是队友,那么竞争值为0,否则就为v[i][j]。

【题解】

  爆搜,C(28,14)*28,其实可以稍加优化,因为分到两个队伍,所以第一个人肯定会分到一个队伍中,搜索可以有,C(27.13)*28,其实可以稍加剪枝,其实这个剪枝有点模糊,就是统计第i个人能产生的最大竞争值,当在过程中这个最大竞争值+当前值 < 暂存答案时,即为剪枝,【最优化剪枝】。

 

【代码】

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 30;
 5 int a[N],b[N];
 6 int A,B,n;
 7 ll v[N][N],ans;
 8 void dfs(int pos,ll sum){
 9     if ( A > n || B > n ){
10         return ;
11     }
12     if ( A == n && B == n ){
13         ans = max(ans,sum);
14         return ;
15     }
16     if( A < n ){
17         a[++A] = pos ;
18         for(int i=1;i<=B;i++){
19             sum += v[pos][b[i]] ;
20         }
21         dfs( pos+1 , sum );
22         for(int i=1;i<=B;i++){
23             sum -= v[pos][b[i]];
24         }
25         A--;
26     }
27     if( B < n ){
28         b[++B] = pos ;
29         for(int i=1;i<=A;i++){
30             sum += v[pos][a[i]] ;
31         }
32         dfs( pos+1 , sum );
33         for(int i=1;i<=A;i++){
34             sum -= v[pos][a[i]];
35         }
36         B--;
37     }
38 }
39 int main()
40 {
41     scanf("%d",&n);
42     for(int i=1;i<=2*n;i++){
43         for(int j=1;j<=2*n;j++){
44             scanf("%lld",&v[i][j]);
45         }
46     }
47     dfs(1,0);
48     printf("%lld\n",ans);
49     return 0;
50 }
爆搜写法

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 30;
 5 int a[N],b[N],A,B,n;
 6 ll v[N][N],p[N],Maxn[N],sum[N];
 7 ll res , ans ;
 8 void dfs(int pos ){
 9     if ( A == n && B == n ){
10         res = max( res , ans );
11         return ;
12     }
13     if( ans + sum[pos] < res )    //当前答案加上后缀 < 已存答案
14         return ;
15     if( A < n ){
16         ll tmp = ans ;
17         a[++A] = pos ;
18         for(int i=1;i<=B;i++)
19             ans += v[pos][b[i]];
20         dfs( pos+1 ) ;
21         A--;
22         ans = tmp ;
23     }
24     if( B < n ){
25         ll tmp = ans ;
26         b[++B] = pos ;
27         for(int i=1;i<=A;i++)
28             ans += v[pos][a[i]];
29         dfs( pos+1);
30         B--;
31         ans = tmp ;
32     }
33 }
34 int main()
35 {
36     scanf("%d",&n);
37     for(int i=1;i<=2*n;i++){
38         for(int j=1;j<=2*n;j++){
39             scanf("%lld",&v[i][j]);
40         }
41     }
42     for(int i=1;i<=2*n;i++){
43         for(int j=1;j<=2*n;j++){
44             p[j] = v[i][j];
45         }
46         sort( p+1,p+1+2*n);
47         for(int j=n+1;j<=2*n;j++){
48             Maxn[i] += p[j] ;
49         }
50     }
51     //预处理sum后缀和,可以在过程中加入进行剪枝
52     for(int i=2*n;i>=1;i--){
53         sum[i] = sum[i+1] + Maxn[i] ;
54     }
55     A = 1 ;
56     a[1] = 1 ;
57     dfs(2);
58     printf("%lld\n",res);
59     return 0;
60 }
稍加剪枝写法

 

posted @ 2019-07-22 10:36  Osea  阅读(348)  评论(0编辑  收藏  举报