zoukankan      html  css  js  c++  java
  • 糖果

    题目大意

          你和你的朋友有一大包糖果,你想把这些糖按照能量尽可能平均分配,输入每种糖果的个数(<=500)与能量(<=200),把这些糖分成两部分使得两部分的能量尽可能接近。

    人想法

           刚看到这道题,一脸懵逼。想了很久很久,打了一个贪心,感觉上是对的。因为时间关系,又没有打对拍。一直找不到错误样例。于是,只水了70分。(由此可得,对拍很重要)

    正解

           原来是DP。设f[i,j]表示前i种糖果,分给两边后差为J的情况是否成立。所以这f数组时boolean类型的。先快排一次,以糖果的能量为关键字,从大到小排。原因是如果先处理了小的会对后面答案造成影响,大的能量很难对区间造成小幅度的改变。再循环枚举,i是1到n,j只要开到0到200就够了。因为糖果能量最大是200,如果差值大于200,那么一定不是最优解。我们先判断f[i-1,j]是否成立(=true),如果为false,则f[i,j]在不选的情况下一定为false。如果成立,则往下做:先第三重循环0到第i种糖果的个数,abs(j+c[i]*k-c[i]*(s[i]-k))表示将k颗糖果分给多的那边,剩下的分给少的那边,反之abs(j-c[i]*k+c[i]*(s[i]-k)的意思则相反。我们就可以进行动态转移方程。(PS:当它的值不大于200时才可以执行)。
    var
    	n,i,j,k:longint;
    	s,c:array[1..100]of longint;
            f:array[0..100,0..200]of boolean;
    procedure kp(l,r:longint);
    var
    	i,j,mid,t:longint;
    begin
    	i:=l;
    	j:=r;
    	mid:=c[(i+j) div 2];
    	repeat
    		while (c[i]>mid) do inc(i);
    		while (c[j]<mid) do dec(j);
    		if (i<=j) then
    		begin
    			t:=c[i];
    			c[i]:=c[j];
    			c[j]:=t;
    			t:=s[i];
    			s[i]:=s[j];
    			s[j]:=t;
    			inc(i);
    			dec(j);
    		end;
    	until i>j;
    	if (i<r) then kp(i,r);
    	if (l<j) then kp(l,j);
    end;
    begin
    	readln(n);
    	for i:=1 to n do
    	begin
    		readln(s[i],c[i]);
    	end;
    	kp(1,n);
            fillchar(f,sizeof(f),false);
            f[0,0]:=true;
    	for i:=1 to n do
    	begin
                    for j:=0 to 200 do
                    begin
                            if (f[i-1,j]) then
                            for k:=0 to s[i] do
                            begin
                                    if (abs(j+c[i]*k-c[i]*(s[i]-k))<=200) then
                                    f[i,abs(j+c[i]*k-c[i]*(s[i]-k))]:=true;//如果大于200,那肯定不是最优解
                                    if (abs(j-c[i]*k+c[i]*(s[i]-k))<=200) then
                                    f[i,abs(j-c[i]*k+c[i]*(s[i]-k))]:=true;
                            end;
                    end;
    	end;
    	for i:=0 to 200 do
                    if (f[n,i]) then
                    begin
                            writeln(i);
                            exit;
                    end;
    end.
    


    如果自己说什麽都做不到而什麽都不去做的话,那就更是什麽都做不到,什麽都不会改变,什麽都不会结束.
  • 相关阅读:
    Codeforces 722C. Destroying Array
    Codeforces 722D. Generating Sets
    【BZOJ】3436: 小K的农场
    数论四·扩展欧几里德
    数论三·约瑟夫问题
    数论二·Eular质数筛法
    #1287 : 数论一·Miller-Rabin质数测试
    树的维护
    可持久化线段树
    【NOIP2016】天天爱跑步
  • 原文地址:https://www.cnblogs.com/Sport-river/p/10390139.html
Copyright © 2011-2022 走看看