• 将元素平分成差值最小的两个集合(DP)


    现有若干物品,要分成较为平均的两部分,分的规则是这样的:

    1)两部分物品的个数最多只能差一个。

    2)每部分物品的权值总和必须要尽可能接近。

    现在请你编写一个程序,给定现在有的物品的个数以及每个物品的权值,求出按上述规则分成两部分后每部分的权值总和。

    输入格式

    第一行为一个整数n(1≤n≤200),表示现在有的物品的个数。

    以下的n行每行一个整数,表示每个物品的权值(1≤ai≤40)。

    输出格式

    只有一行,包含两个数,即分成的每部分的权值总和,较小的一个值放在前面,两个数用空格隔开。

    样例输入

    3
    35
    20
    32

    样例输出

    35 52

    对于本题,因为需要再计算过程中保证你计算的结果是n2 或 n2+1个物品。所以这个时候我们就必须要使用二维数组,来记录你使用物品个数。

    最后我们在找出n2 或 n2+1(n是奇数)个物品中权值最大的就行了。

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <string>
     5 #include <math.h>
     6 #include <algorithm>
     7 #include <vector>
     8 #include <stack>
     9 #include <queue>
    10 #include <set>
    11 #include <map>
    12 #include <sstream>
    13 #include <ctime>
    14 const int INF=0x3f3f3f3f;
    15 typedef long long LL;
    16 const int mod=1e9+9;
    17 const LL MOD=1e9+7;
    18 const double PI = acos(-1);
    19 const double eps =1e-8;
    20 #define Bug cout<<"---------------------"<<endl
    21 const int maxn=1e5+10;
    22 using namespace std;
    23 
    24 int a[205];
    25 int dp[205][205*20];//dp[i][j]表示当前有i个物品总权值为j 
    26 
    27 int main()
    28 {
    29     #ifdef DEBUG
    30     freopen("sample.txt","r",stdin);
    31     #endif
    32 //    ios_base::sync_with_stdio(false);
    33 //    cin.tie(NULL);
    34     
    35     int n;
    36     scanf("%d",&n);
    37     int sum=0;
    38     for(int i=1;i<=n;i++)
    39     {
    40         scanf("%d",&a[i]);
    41         sum+=a[i];
    42     }
    43     dp[0][0]=1;
    44     for(int i=1;i<=n;i++)
    45     {
    46         for(int j=n/2+1;j>=0;j--)
    47         {
    48             for(int k=sum/2;k>=0;k--)
    49             {
    50                 if(dp[j][k]) dp[j+1][k+a[i]]=1;
    51             }
    52         }
    53     }
    54     for(int i=sum/2;i>=0;i--)
    55     {
    56         if(dp[n/2][i]||(dp[n/2+1][i]&&n&1))
    57         {
    58             printf("%d %d
    ",i,sum-i);
    59             break;
    60         }
    61     }
    62     
    63     return 0;
    64 }

    现有N个物品,每块物品有一个权值, 现在想将这N个物品分成权值相同的两部分,可以从这N个物品中任取M(1≤M≤N)个来构建。但是不知道这些物品能否使分成的两部分具有同样的权值,也不

     知道如果能分成权值相同的两部分,每部分的最大权值是多少。

    给定物品的数量N(1≤N≤100)和每个物品的权值wi ( N个物品的权值总和不超过2000 )。

    你的任务是判断能否在这些物品中挑一部分,把他们分成权值相同的两部分,如果能,则输出所能分成两部分的最大权值和,否则输出" Impossible"。

    输入格式

    输入的第一行为一个数 N,表示物品的数量。

    第二行为 N 个数,第 i 个数表示第 i 个物品的权值。

    输出格式

    输出仅包含一行,如果能分成权值相同的两部分,则输出每部分的最大权值和,否则输出一个字符串"Impossible"。

    样例输入

    5
    1 3 4 5 2

    样例输出

    7

    本题用dp[i][j]表示已处理i件物品,而分成的两部分权值差为j的一种状态。

    所以我们对这两部分我们有三种操作

    1)把第i个物品放入总权值大的一部分中,大的变得更大

    2)把第i个物品放入总权值小的一部分中,然后就会发生两种情况

    (1)小的变成大的

    (2)小的还是小的

     所以我们有三种状态转移方程。对应的代入如上。

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <string>
     5 #include <math.h>
     6 #include <algorithm>
     7 #include <vector>
     8 #include <stack>
     9 #include <queue>
    10 #include <set>
    11 #include <map>
    12 #include <sstream>
    13 #include <ctime>
    14 const int INF=0x3f3f3f3f;
    15 typedef long long LL;
    16 const int mod=1e9+7;
    17 const double PI = acos(-1);
    18 const double eps =1e-8;
    19 #define Bug cout<<"---------------------"<<endl
    20 const int maxn=1e5+10;
    21 using namespace std;
    22 
    23 int a[105];
    24 int dp[105][2005];
    25 
    26 int main()
    27 {
    28     #ifdef DEBUG
    29     freopen("sample.txt","r",stdin);
    30     #endif
    31 //    ios_base::sync_with_stdio(false);
    32 //    cin.tie(NULL);
    33     
    34     int n;
    35     scanf("%d",&n);
    36     int sum=0;
    37     for(int i=1;i<=n;i++)
    38         scanf("%d",&a[i]);
    39     memset(dp,-1,sizeof(dp));
    40     dp[0][0]=0;
    41     for(int i=1;i<=n;i++)
    42     {
    43         sum+=a[i];
    44         for(int j=0;j<=sum;j++)
    45         {
    46             if(dp[i-1][j] > dp[i][j])//不选(初始化)
    47                 dp[i][j] = dp[i-1][j];
    48             if(j >= a[i] && dp[i-1][j-a[i]] >= 0)//大 -> 大 
    49                 dp[i][j] = max(dp[i][j],dp[i-1][j-a[i]]);
    50             if(dp[i-1][j+a[i]] >= 0)//小 -> 小 
    51                 dp[i][j] = max(dp[i][j],dp[i-1][j+a[i]]+a[i]);
    52             if(a[i] >= j && dp[i-1][a[i]-j] >= 0)// 小 -> 大 
    53                 dp[i][j] = max(dp[i][j],dp[i-1][a[i]-j]+a[i]-j);
    54         }
    55     }
    56     if(dp[n][0]) printf("%d
    ",dp[n][0]);
    57     else printf("Impossible
    ");
    58     
    59     return 0;
    60 }

    -

  • 相关阅读:
    Android BroadcastReceiver 接收收到短信的广播
    Android ContenObserver 监听联系人数据变化
    Android 通过AIDL在两个APP之间Service通信
    Android studio安装和问题
    Android 底部导航栏实现一 Fragment-replace
    Android ImgView属性
    Android TextView常用属性
    Android颜色配置器
    Android gravity和layout_gravity的区别
    Android 组件的三种点击事件写法
  • 原文地址:https://www.cnblogs.com/jiamian/p/12219569.html
Copyright © 2020-2023  润新知