JOJ 1903 1129 1157 1278

来源:互联网 发布:痔疮 根治方法 知乎 编辑:程序博客网 时间:2024/05/17 04:42

JOJ 1903 Tug of War: http://acm.jlu.edu.cn/joj/showproblem.php?pid=1903
题目概述:给N正整数,每个正整数在1450之间,N最大是100,要求把N正整数分成两组,两个分组包含的正整数的数目之差不能超过1,并且使得两个分组所含的正整数的和最接近。比如三个正整数10090200,显然分成{10090}和{200},这时两组数和的差达到最小,为10
这个题目在《编程之美》的数组分割问题中给出了三种分析和实现,第一种方法是随机交换,但有可能得到错误的解,第二种是类似背包问题的动态规划,时间复杂度2N次方,第三种是根据结果分类,时间复杂度为O(sum * N)sum是这N个数的和。详见:http://blog.csdn.net/jcwKyl/archive/2009/02/23/3926444.aspx。这个题目的时限为15秒,第二种解法代码提交为3秒,第三种解法提交为1秒。各OJ上有大量0.00S的成绩,后来发现0.00S的成绩用的是随机交换。
 
JOJ 1129 Divisibility: http://acm.jlu.edu.cn/joj/showproblem.php?pid=1129
题目概述:输入N整数(每个整数绝对值不超过10000)和一个正整数K(2<=K<=100),可以在两个整数间放置加号或减号。问是不是存在一种放置加减号的方法,使得N整数的运算结果能被K整除。
这个题可以模仿《编程之美》在“数组分割”问题中使用的方法三的思路,被K整除的意思就是模K的结果为0,根据模K的结果将每次得到的中间结果分类,假设S(i)表示当前i整数的任意加减组合所得到的所有结果,这些全部结果根据模K的余数最多有K类。当处理第i+1个整数a[i+1]时,有S(i+1)= { (x + a[i+1]) mod k | x belongs to S(i) }。这样,可以在O(N*K)的时间复杂度内得出结果。代码如下:
#include <stdio.h>
#include <string.h>
 
int main() {
    int i, j, t, kase,n, k, ti;
    char flag1[128], flag2[128], *pre, *cur, *tmp;
 
    scanf("%d", &kase);
    while(kase--) {
        scanf("%d%d", &n, &k);
 
        memset(flag1, 0, sizeof(flag1));
        memset(flag2, 0, sizeof(flag2));
       
        scanf("%d", &t);
        cur = flag1;
        pre = flag2;
        t %= k;
        if(t < 0) t += k;
        cur[t]= 1;
       
        for(i = 0; i < n - 1; i++) {
            scanf("%d", &t);
            for(j = 0; j < k;j++) {
                if(cur[j]) {
                    ti = (j + t) % k;
                    if(ti < 0) ti += k;
                    pre[ti] = 1;
                   
                    ti = (j - t) % k;
                    if(ti < 0) ti += k;
                    pre[ti] = 1;
                    cur[j] = 0;
                }
            }
            tmp = cur;
            cur = pre;
            pre = tmp;
        }
        printf("%s/n", cur[0]?"Divisible":"Not divisible");
    }
 
}
 
 
JOJ 1157 Station Balance: http://acm.jlu.edu.cn/joj/showproblem.php?pid=1157
题目概述:有C盒子和N小球(N<=2*C),每个盒子可以放0个、1个或2个小球。设N小球的重量分别为M1,M2, …, Mn。把N小球放到C盒子里,使每个盒子中放的小球的重量尽可能平均。设Ave表示每个盒子应该放的小球的重量,即Ave = (M1 + M2 + … + Mn) / C。题目的要求就是使下面的式子取值最小:SUM( | CMi – Ave | ),i = 1, 2, … ,CCMi表示第i盒子中放的球的总重量。
题目中的C不大于5。但这个题目可以用贪心:将N小球被上2*C-N重量为0的小球,现在得到了2*C重量,假设这2*C重量从小到大排序为:M1,M2, …, M2c。贪心策略就是开头取一个末尾取一个放到一个盒子里,如上即将M1M2c放在第一个盒子里,将M2M2c-1放到第二个盒子里,如此类推。
贪心证明:证明在最优解中,M1M2c放在同一个盒子里。假设T是这个问题的一个最优解,如果T中某个盒子里放的是M1M2c,则已证。否则,假设T中有两个盒子,分别放着小球(M1,Mi), (Mj, M2c)。设这两个盒子的部分和为sum2:

 

JOJ 1278 Simply Subsets: http://acm.jlu.edu.cn/joj/showproblem.php?pid=1278
输入两个集合的元素,判断两个集合的包含、相等、相交关系。输入数据时,一行中有所有的一个集合的元素,使用getlineistringstream非常方便。

原创粉丝点击