zoukankan      html  css  js  c++  java
  • 【搜索】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
    ",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
    ",res);
    59     return 0;
    60 }
    稍加剪枝写法
  • 相关阅读:
    太鼓达人
    DB2中循环日期跑数据
    DB2分区表删除和添加分区
    DB2日常运维之总结(转)
    oracle SQL not in null,单列,复合列
    利用rlwrap配置linux下oracle sqlplus 历史记录回调
    Oracle非默认监听的处理会遇到的问题以及处理方法
    Sqlserver循环嵌套
    rman全备份异机恢复
    Windows系统下Oracle数据库冷备
  • 原文地址:https://www.cnblogs.com/Osea/p/11224432.html
Copyright © 2011-2022 走看看