zoukankan      html  css  js  c++  java
  • 将元素平分成差值最小的两个集合(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 }

    -

  • 相关阅读:
    OK335x mksd.sh hacking
    Qt jsoncpp 对象拷贝、删除、函数调用 demo
    OK335xS 256M 512M nand flash make ubifs hacking
    Qt QScrollArea and layout in code
    JsonCpp Documentation
    Qt 4.8.5 jsoncpp lib
    Oracle数据库生成UUID
    freemarker得到数组的长度
    FreeMarker中if标签内的判断条件
    freemarker语法
  • 原文地址:https://www.cnblogs.com/jiamian/p/12219569.html
Copyright © 2011-2022 走看看