首页 > 试题广场 >

第二题

[编程题]第二题
  • 热度指数:8138 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
一个数组中有若干正整数,将此数组划分为两个子数组,使得两个子数组各元素之和a,b的差最小,对于非法输入应该输出ERROR。

输入描述:
数组中的元素


输出描述:
降序输出两个子数组的元素和
示例1

输入

10 20 30 10 10
10 20 abc 10 10

输出

40 40
ERROR
#include <iostream>

using namespace std;

bool isDigit(char c){  // 判断是否为数字
    if(c>'9'||c<'0'){
        return false;
    }else{
        return true;
    }
}
int ch2num(char c){
    return c-'0';
}
int max(int a,int b){
    if(a>b) return a;
    else return b;
}

int num[1000];// 先开1000试试
int idx =0;
bool flag; //判断是否为非法输入
int sum=0;
int half = 0;
int first =0;  // 存储当前搜索最大结果

void init(){
    first =0;
    flag = false;
    idx=0;
    sum = half = 0;
}

void DFS(int i,int sum){
    if(i==idx) return; // 搜索完全部数组内容结束
    else if(sum + num[i]<=half){
        first = max(sum+num[i],first);
        if(first ==half) return ;
        DFS(i+1,sum+num[i]);
    }
    DFS(i+1,sum);
}

int main(){
    string s;
    while(getline(cin,s)){
        init();
        int length = s.length();
        for(int i=0;i<length;i++){
            if(s[i]==' ') continue;
            else{
                int x = ch2num(s[i]);
                if(isDigit(s[i])){
                    int j= i+1;
                    int temp =0;
                    temp = temp*10 + x;
                    while(isDigit(s[j])){
                        x = ch2num(s[j]);
                        temp = temp*10 + x;
                        j++;
                    }
                    num[idx++] = temp;
                    i = j;
                }else{
                    flag = true;// 非法
                }
            }
        }
        if(flag){
            cout << "ERROR"<<endl;
        }else{
            for(int i=0;i<idx;i++){
                sum = sum + num[i];
            }
            half = sum/2;
            DFS(0,0);
            cout<<sum-first<<" "<<first<<endl;
        }

    }
    return 0;
}

发表于 2019-09-06 14:49:52 回复(1)
#include <iostream>
#include <string>
#include <vector>
#include <numeric>
#include <bitset>
#include <algorithm>
#include <limits>
#include <functional>
using namespace std;

bool sto_vec(const string &str,vector<int>& vec){//把数组分离出来
	int count =0;
	for(int i(0);i<str.size();++i){
		if(str[i]>='0' && str[i]<= '9')
			count++;
		else if(str[i] == ' ' && count !=0){
			vec.push_back(stoi(str.substr(i-count,count)));
			count=0;
		}else
			return false;

	}
	if(count>0)
		vec.push_back(stoi(str.substr(str.size()-count,count)));
	return true;
}


//方法一:时间复杂度2^n,需要减枝
int dp_func(int i,int j,const vector<int>& vec){ //递归模拟动态规划0-1背包,j为代价,时间复杂度太大,舍去;
	if(i==0 || j==0) return 0;
	auto temp (dp_func(i-1,j,vec));//先算不取这个值的,成功可能性大
	if(j<vec[i] || temp == j){
		return temp;
	}else{
		return max(temp,dp_func(i-1,j-vec[i],vec)+vec[i]);
	}
}

//方法二:时间复杂度2^n,需要减枝
void dfs(int i,const int& half,int now_sum,const vector<int>& vec,int& ans){
	if(i==vec.size()) return;
	auto temp(now_sum+vec[i]);
	if(temp == half){
		ans =half;
		return;
	}else if(temp<half){
		ans = max(ans,temp);
		dfs(i+1,half,temp,vec,ans);//选中
		if(ans == half)return;
	}
	//不选中
	dfs(i+1,half,now_sum,vec,ans);
	return ;
}

//方法三,参考大神们的;时间复杂度2^(n/2)。运行时间:40ms
//思想:把数组分成左右两半,左边(长度left)各种元素相加可能性有2^left种;右边有2^righ种;
//然后寻找所有可能性中,左边部分+右边部分小于等于half的最大值;
//我这儿为了思路清晰,把大神的许多优化去掉了
int solve(const vector<int>& vec,const int& half){
	int len(vec.size());
	int left(len/2);
	int right(len-left);
	int left_status(1<<left);//2^left
	int right_status(1<<right);

	bitset<32> assist; 
	vector<int>left_sum;//左半各种相加的可能性
	for(int i(0);i<left_status;++i){
		assist=i;
		int temp =0;
		for(int j(0);j<left;++j){
			if(assist[j]){
				temp += vec[j];
			}
		}
		if(temp<=half){
			left_sum.push_back(temp);
		}
	}
	sort(left_sum.begin(),left_sum.end());

	vector<int>right_sum;//右半各种相加的可能性
	for(int i(0);i<right_status;++i){
		assist=i;
		int temp =0;
		for(int j(0);j<right;++j){
			if(assist[j]){
				temp += vec[j+left];
			}
		}
		if(temp<=half){
			right_sum.push_back(temp);
		}
	}

	//寻找左+右小于等于half且最接近half
	int ans(numeric_limits<int>::min());
	for(const auto& item:right_sum){
		auto iter = upper_bound(left_sum.begin(), left_sum.end(), half - item);//*iter为left_sum中满足*iter>half - item的第一个值,既满足item + *(--iter)<=half的最大值;
		if (iter != left_sum.begin()){
			--iter;
			ans = max(ans, item + *iter);
		}
	}
	return ans;
}

int main(){
	string str;
	int ans;
	while(getline(cin,str) && !str.empty()){
		vector<int> vec;
		if(!sto_vec(str,vec)){
			cout<<"ERROR"<<endl;
			continue;
		}
		int sum = accumulate(vec.begin(),vec.end(),0);
		int half = sum/2;

		//大的排前面能大大优化性能。对方法一、运行时间:185ms;小的排前为516ms。
		//对方法二:运行时间:89ms;小的在前运行时间:238ms。
		//对方法三:运行时间:35ms;小的在前运行时间:32ms,相差不大,小的在前貌似更优
		//sort(vec.begin(),vec.end(),greater<int>());//方法一、二使用
		//sort(vec.begin(),vec.end());//方法三使用

		//方法一,递归模拟动态规划0-1背包,时间复杂度太大,运行时间:317ms
		//sort(vec.begin(),vec.end(),greater<int>());
		//vec.insert(vec.begin(),0);//第一个元素为0,占位,为了序号从1开始,不从0开始;
		//ans = dp_func(vec.size()-1,half,vec);

		//方法二
		//sort(vec.begin(),vec.end(),greater<int>());
		//dfs(0,half,0,vec,ans=0);

		//方法三
		sort(vec.begin(),vec.end());
		ans = solve(vec,half);
		cout<<sum-ans<<' '<<ans<<endl;
	}
	return 0;
}
三种方法:1、模拟0-1背包,2,深度优先搜索。两种时间复杂度都是2^n,都需要减枝。3划分为两半,参考大神的解法。提前排序能优化性能。时间复杂度待商榷
编辑于 2020-03-06 10:07:14 回复(0)
坑1:子数组不一定是连续的
坑2:子数组和可能会很大很大
问题等价于01背包,可以看做在数组中选出若干个数,使得选出的数字的和在不超过sum/2的情况下最大。(两个子数组的和越接近sum/2,他们的差越小)具体可以搜索和差值最小子数组参考别人的博文。
但是这个题目没办法直接用动态规划,因为这个和会非常非常大,导致状态空间过大,会内存溢出,所以最后AC的代码还是用了搜索+剪枝,直接搜索所有可能的选择。
PS:如果有使用成功使用动态规划的解法请告诉我
编辑于 2019-02-19 22:23:09 回复(3)
本题如用递归最需要注意的地方就是一旦结果到达了和的一半,递归就应该立刻停止,否则就会超时。本题的大型用例都是可以达到一半的,事实上,如果是一般的情况,例如奇数个5,只用三十几个就可以让讨论区中通过的代码全部超时。我猜测很多使用dfs但是超时的同学都是因为这个原因。
发表于 2020-04-22 16:56:14 回复(0)
DFS的话记得设置,找到最优解之后,即数组相差为0之后,就立刻停止所有的搜索。
这样就不会超时了。
发表于 2021-03-20 15:39:40 回复(0)
背包问题

有 a + b = sum;
  a >= b;
则 b <= sum/2

因此可以转化为 问题
对于给定的序列 nums, 能够构成 1----sum/2 问题

然后取得最大的能够构成的 b 即可

就是不知道输入为啥👨‍🏫出错

#include<iostream>
(720)#include<vector>
#include<string>
using namespace std;

// dp 0-1 背包问题
void package(vector<int> &nums){
    int n = nums.size() , sum = 0;
    for(int num : nums) sum += num;
    int target = sum/2;
    // 不能重复时
    vector<bool> dp(target + 1, 0);
    dp[0] = true;
    
    for(int num : nums){
        for(int i = target; i >= num ; i--){
            dp[i] = dp[i] || dp[i-num];
        }
    }
    int b = 0;
    for(int i= target; i >= 0; i--){
        if(dp[i]) {b = i; break;}
    }
    printf("%d %d\n",b,sum-b);
}


int main()
{
    string str ;
    while (getline(cin,str))
    {    
        bool ok = true;
        for (int i = 0; i < str.size(); i++)
        {
            if (str[i] != ' ' && !(str[i] >= '0' && str[i] <= '9'))
            {
                ok = false;
                break;
            }
        }
        if (!ok)
        {
            cout << "ERROR" << endl;
            continue;
        }
        vector<int> nums;
        int prev = 0;
        for (int i = 0; i < str.size(); i++)
        {
            char c = str[i];
            if (c == ' ' )
            { 
                nums.push_back(stoi(str.substr(prev,i-prev)));
                prev = i + 1;
            }
        }
        nums.push_back(stoi(str.substr(prev,str.size()-prev)));
        package(nums);

    }
    return 0;
}



发表于 2020-05-06 21:33:52 回复(0)
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const int MAXN = 10000;

int main() {
    string str;
    while(getline(cin, str)) {
        bool flag = true; //记录是否全为数字
        long long arr[MAXN] = {0};
        int num = 0; //记录当前正在处理哪个数字
        for(int i = 0; i < str.size(); ++i){
            if(str[i] == ' ') {
                num++;
            } else {
                if(str[i] < '0' || str[i] > '9') {
                    flag = false; //有非数字出现
                } else {
                    arr[num] = arr[num] * 10 + str[i] - '0';
                }
            }
        }
        if(!flag) {
            cout << "ERROR" << endl;
            continue;
        }
        num++;
        long long dp[num], total = 0, mid;
        for(int i = 0; i < num; ++i) {
            dp[i] = arr[i];
            total += arr[i];
        }
        mid = total / 2;
        for(int i = 1; i < num; ++i) {
            for(int j = 0; j < i; ++j) {
                dp[i] = abs(dp[j] + arr[i] - mid) < abs(dp[i] - mid) ? dp[j] + arr[i] : dp[i];
            }
        }
        long long sum1 = dp[0], sum2;
        for(int i = 1; i < num; ++i) {
            sum1 = abs(dp[i] - mid) < abs(sum1 - mid) ? dp[i] : sum1;
        }
        sum2 = total - sum1;
        if(sum1 < sum2) { //方便后续降序输出
            swap(sum1, sum2);
        }
        cout << sum1 << " " << sum2 << endl;
    }
    return 0;
}

//所有整数之和为total,被分为了两个数组,数组1的和为sum,数组2的和为total - sum
//则两个数组各元素之和的绝对值为abs(total-sum-sum) = abs(total-2*sum) = abs(2*sum-total)
//sum的值有三种可能:(1)sum > total / 2 (2)sum = total / 2 (3)sum < total / 2
//当sum > total / 2时,有abs(total-sum-sum) = 2*sum-total
//要使得这个结果最小,应该要使得sum的值在满足sum > total / 2的条件下最小
//当sum < total / 2时,有abs(total-sum-sum) = total - 2*sum
//要使得这个结果最小,应该要使得sum的值在满足sum < total / 2的条件下最大
//设置一个数组:dp[],固定dp的一端会使得问题更简单:
//dp[i]表示从arr[0]到arr[i]中的所有以arr[i]为最后一个元素的子序列中各元素之和最接近total / 2的那个子序列各元素之和
//最后再从dp[0]到dp[n]中选择最接近total / 2的即可(注意不是dp[]的最后一个元素)
//dp[i]的初值为arr[i]
//状态转移方程为:
//dp[i]=abs(dp[j]+arr[i]-(total / 2))<abs(dp[i]-(total/2)) ? dp[j]+arr[i] : dp[i]
//这里比较的是绝对值,故转态转移方程与常见的有所不同
//其中:dp[i]=dp[j]+arr[i]表示在dp[j]的基础上加上arr[i]后更接近total/2
//应该用双重循环,递推确定dp[i],二重循环中j < i

//拿示例的输入来手动模拟这个过程以说明思路:
//(0)先根据输入的数据:arr[5] = {10,20,30,10,10},确定total=80,记mid=total/2 = 40;
//(1)建立dp[5],各元素初值为arr[i],dp[0]无需分析:dp[0] = arr[0] = 10
//(2)abs(dp[0]+arr[1]-mid)<abs(dp[1]-mid),所以dp[1] = dp[0] + arr[1] = 10 + 20 = 30;
//(3)abs(dp[0]+arr[2]-mid)<abs(dp[2]-mid),所以dp[2] = dp[0] + arr[2] = 10 + 30 = 40;
//     abs(dp[1]+arr[2]-mid)>abs(dp[2]-mid),所以dp[2] = dp[2]= 40;
//(4)abs(dp[0]+arr[3]-mid)<abs(dp[3]-mid),所以dp[3] = dp[0] + arr[3] = 10 + 10 = 20;
//     abs(dp[1]+arr[3]-mid)<abs(dp[3]-mid),所以dp[3] = dp[1] + arr[3] = 30 + 10 = 40;
//     abs(dp[2]+arr[3]-mid)>abs(dp[3]-mid),所以dp[3] = dp[3]= 40;
//(5)abs(dp[0]+arr[4]-mid)<abs(dp[4]-mid),所以dp[4] = dp[0] + arr[4] = 10 + 10 = 20;
//     abs(dp[1]+arr[4]-mid)<abs(dp[4]-mid),所以dp[4] = dp[1] + arr[4] = 30 + 10 = 40;
//     abs(dp[2]+arr[4]-mid)>abs(dp[4]-mid),所以dp[4] = dp[4]= 40;
//     abs(dp[3]+arr[4]-mid)>abs(dp[4]-mid),所以dp[4] = dp[4]= 40;
//(6)此时dp[] = {10,40,40,40,40},其中最接近mid的元素为40;
//     因此可以得到子数组1各元素之和为40,子数组2的各元素之和为total - 40 = 40;
//     输出即可
// 大整数例子未通过,求帮助
发表于 2022-03-15 14:54:25 回复(0)
//借鉴于:https://blog.csdn.net/hh1986170901/article/details/105000680
//方法就是DFS剪枝
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
int handle(string s,int a[]){
    int count = 0;
    int i = 0;
    while(s[i] != '\n' && i < s.size()){
        if(s[i] >= '0' && s[i] <= '9'){
            while(s[i] >= '0' && s[i] <= '9'){
                a[count] = a[count] * 10 + s[i] - '0';
                i++;
                if(i >= s.size()) break;
            }
            count++;
            continue;
        }else if(s[i] != ' ' && s[i] != '\n'){
            return 0;
        }
        i++;
    }
    for(int i = 0;i < count;i++)
        if(a[i] == 0)
            return 0;
    return count;
}
bool cmp(int a,int b){
    return a > b;
}
int a[50000];
int ans;
int n;
int half;
void dfs(int i,int sum){
    if(i >= n || sum + (n-i) * a[i] < ans)
        return;
    if(sum+a[i] <= half){
        ans = max(ans,sum+a[i]);
        dfs(i+1,sum+a[i]);
    }
    dfs(i+1,sum);
}

int main(){
    string s;
    while(getline(cin,s)){
        memset(a,0,sizeof(a));
        n = handle(s,a);
        if(!n){
            cout << "ERROR" << endl;
            continue;
        }
        int sum = 0;
        for(int i = 0;i < n;i++)
            sum += a[i];
        half = sum / 2;
        sort(a,a+n,cmp);
        ans = 0;
        dfs(0,0);
        cout << sum - ans << " " << ans << endl;
    }
    return 0;
}

发表于 2021-03-10 18:14:27 回复(0)

dfs加剪枝

1、值等于一半,可以退出
2、剩下的值全部选上也不能更新当前答案,可以退出(用前缀和)
3、若加上当前元素,大于一半,则不能加

#include <iostream>
#include <sstream>
#include <cstring>
using namespace std;

typedef long long  LL;
const int N = 1000;
int q[N];
LL pre[N];
int idx;
bool f[N];
LL S,sum, res = 0;

void dfs(int u)
{
    if(res == S/2) return ;
    if(u == idx)
    {
        if(sum <= S / 2)
        {
            res = max(res,sum);
            return ;
        }
    }
    if(pre[idx] - pre[u] + sum <= res) return;

    if((LL)q[u] + sum <= S / 2)
    {
        sum += q[u];
        dfs(u + 1);
        sum -= q[u];
    }
    dfs(u + 1);

}

int main()
{
    string s;
    while(getline(cin,s))
    {
        if(s.size() == 0) continue;
        bool flag = false;

        stringstream ss;
        ss << s;

        idx =0;
        S = 0;
        string str;
        while(ss >> str)
        {
            LL a = 0;
             for(int i = 0; i < str.size(); i ++ )
             {
                 if(str[i] >= '0' && str[i] <= '9')
                     a = a * 10 + str[i] - '0';
                 else 
                 {
                     flag  = true;
                     break;
                 }
             }
            if(flag) break;
            q[idx ++ ] = a;
            pre[idx] = pre[idx - 1] + a;
            S += a;

        }
        if(flag)
        {
            puts("ERROR");
            continue;
        }

        //此时q中存储了数字,idx中存储了有多少个
        res = 0;
        sum = 0;
        memset(f,false,sizeof f);
        dfs(0);
        S -= res;
        if(res < S) swap(res,S);
        printf("%lld %lld\n",res,S);
    }
    return 0;
}
发表于 2021-02-24 15:30:53 回复(0)
#include<iostream>
#include<cstring>
#include<string>
using namespace std;

int d[100];
int j,min_sum,s1,s2,sum;
bool GetNum(string s)
{
    j = 0;
    sum = 0;
    memset(d,0,sizeof(d));
    for(int i = 0;i < s.size();i++)
    {
        if(s[i] == ' ')
        {
            j++;
            continue;
        }
        if(s[i] >= '0' && s[i] <= '9')
            d[j] = d[j] * 10 + s[i] - '0';
        else return false;
    }
    j++;
    for(int i = 0;i < j;i++) sum += d[i];
    return true;
}

void DFS(int sum1,int i)
{
    if(sum1 > sum / 2 || s1 == s2) return;
    if(i == j)
    {
        if(abs(sum - sum1 * 2) < min_sum)
        {
            min_sum = abs(sum - sum1 * 2);
            s1 = sum1,s2 = sum - sum1;
        }
        return;
    }
    DFS(sum1,i + 1);
    DFS(sum1 + d[i],i + 1);
}

int main()
{
    string s;
    while(getline(cin,s))
    {
        if(!GetNum(s)) cout << "ERROR" << endl;
        else 
        {
            min_sum = INT32_MAX;
            s1 = 0,s2 = 1;
            DFS(0,0);
            if(s1 > s2)
                cout << s1 << " " << s2 << endl;
            else
                cout << s2 << " " << s1 << endl;
        }
    }
    return 0;
}

发表于 2021-02-23 23:07:08 回复(0)
思路1: 视为01背包问题。背包容量可为 2^32 ,则辅助数组,至少需要 (2^32)*4B,约 16G。超内存了。
思路2: DFS。输入数组A,元素个数为n。将一维数组视为 n 层的满二叉树。第 i 个元素是否被包含,作为二叉树的分叉条件。通过 DFS 遍历数组元素组合,可访问所有的可能组合。
          剪支:包含元素的和 > sum / 2,停止子树遍历
                    包含元素的和 == sum / 2,停止所有 DFS

#include <iostream>
#include <string>
#include <vector>
#include <limits.h>
#include <unordered_set>
#include <unordered_map>

void DFS(int i, int sum, int& max, const int c, const std::vector<int>& v){
    if (i >= v.size()){
        return;
    }
    if (sum > c){
        return;
    }
    if (sum + v[i] == c){
        max = std::max(max, sum + v[i]);
        return;
    }
    if (sum + v[i] < c){
        max = std::max(max, sum + v[i]);
        DFS(i+1, sum + v[i], max, c, v);
    }
    if (max == c){
        return;
    }
    DFS(i+1, sum, max, c, v);
}

int main(){
    std::string line;
    while(std::getline(std::cin, line)){
        std::vector<int> v;
        int start = 0;
        bool error = false;
        int sum = 0;
        for (int i = 0; i < line.size(); i++){
            if ((line[i]< '0' || line[i] > '9') && line[i]!= ' ' ){
                error = true;
                break;
            }
            
            if (line[i] == ' '){
                int num = std::stoi(line.substr(start, i - start));
                v.push_back(num);
                sum += num;
                start = i + 1;
            }
        }
        if (error){
            std::cout << "ERROR" << std::endl;
            continue;
        }
        int num = std::stoi(line.substr(start));
        v.push_back(num);
        sum += num;
        int c = sum / 2;
        int max = 0;
        DFS(0, 0, max, c, v);
        std::cout << sum - max << " " << max << std::endl;
    }
    return 0;
}
发表于 2021-02-04 22:04:04 回复(0)
python 是不是输入输出有问题啊,我去掉输入循环,有1%的通过率,加上输入循环,直接报超时0%通过率,算法复杂度也不高啊。。。
import sys

def DFS(num_array,result_half,num_index,tmp_sum):
    if tmp_sum==result_half:
        return tmp_sum
    if num_index==len(num_array):
        return tmp_sum
    
    tmp_sum2=DFS(num_array,result_half,num_index+1,tmp_sum)
    if (tmp_sum+num_array[num_index])<=result_half:
        tmp_sum1=DFS(num_array,result_half,num_index+1,tmp_sum+num_array[num_index])
        if tmp_sum1<tmp_sum2:
            return tmp_sum2 
        else:
            return tmp_sum1
    else:
        return tmp_sum2

def check_num(num_str):
    for a in num_str:
        if a not in '1234567890 \n':
            return False
    return True
    
        
    
    
    


while True:
    
    num_str=sys.stdin.readline()
    if not num_str:
        break
    if check_num(num_str)==False:
        print('ERROR')
        continue
    num_array=list(map(int,num_str.split()))
    result=DFS(num_array,sum(num_array)/2,0,0)
    print(sum(num_array)-result,result)
    

发表于 2020-08-23 09:52:08 回复(0)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAX=25;
bool isGo; //是否继续 
LL n, avg, ans, re[MAX];
void DFS(LL index, LL cnt){
	if(isGo==false || index>=n){ //如果不加isGo判断,那么会超时
        if(ans == avg) isGo = false;
        return ;
    }
    if(abs(ans-avg) > abs(cnt-avg)) ans = cnt; //要每次都判断一下
    DFS(index+1, cnt+re[index+1]); //选
    DFS(index+1, cnt); //不选
}
int main(){
    bool flag; //是否非法
    LL i, t, sum;
    string s;
    while(getline(cin, s)){
        s += ' ';
        n = 0, t = 0, sum=0; //sum记录总数
        flag = false;
        for(i=0; i<s.size(); i++){
            if(s[i] == ' '){
                re[n++] = t;
                sum += t;
                t = 0;
            }else{
                if(s[i]<'0' || s[i]>'9'){
                    flag = true;
                    break;
                }
                t = t*10 + (s[i]-'0');
            }
        }
        if(flag){
            printf("ERROR\n");
            continue;
        }
        avg = sum / 2;
        ans = 0;
        isGo = true;
        DFS(-1, 0);
        if(sum-ans > ans) printf("%lld %lld\n", sum-ans, ans);
        else printf("%lld %lld\n", ans, sum-ans);
    }
    return 0;
}
这个题也是神了~之前在本地测试出现各种毛病,最后气得直接提交,然后过了。。。。后来回过头来仔细思考代码,发现isGo这个条件的设置竟然如此的重要。。。不知道是不是和测试数据有关的缘故,毕竟改变isGo的条件是找到了均值(即这个条件似乎太苛刻了)。
发表于 2020-04-23 17:44:39 回复(0)
感觉0-1背包能做,但是溢出;还是剪枝的DFS吧;
发表于 2020-04-09 18:59:09 回复(0)
求助,全部超时啊!!!!看了其他人的,感觉DFS的思路复杂度是一样的啊,为什么全部超时,但是样例我能过。
#include<iostream>
(720)#include<string>
#include<cmath>
using namespace std;
const int maxn=10010;
int sum,half_sum,near,bestsum;
int a[maxn];
void DFS(int index,int nowsum,int n){
	if(index==n) return;
	if(abs(nowsum-half_sum)<near){
		near=abs(nowsum-half_sum); 
		bestsum=nowsum;
	}
	if(nowsum<half_sum){
		DFS(index+1,nowsum+a[index],n);
    }
	DFS(index+1,nowsum,n);
}
int main(){
	string s;
	while(getline(cin,s)){
		int len=s.size();
		bool flag=true;
		for(int i=0;i<len;i++){
			if(!(((s[i]>='0' && s[i]<='9')) || (s[i]==' '))){
				flag=false;
				break;
			}
		}
		if(flag==false) cout << "ERROR" << endl;
		else{
			int i=0,cnt=0,j=0;
			sum=0;
			while(i<len){
				if(s[j]>='0' && s[j]<='9') j++;
				else{
					string temp=s.substr(i,j-i);
					a[cnt]=stoi(temp);
					sum+=a[cnt]; 
					cnt++;
					j=j+1;
					i=j;
				}
			}
			// cout << a[0] << a[1] << a[2] << a[3] << a[4];
			half_sum=sum/2,near=1000000;
			DFS(0,0,cnt);
			int ans1=max(sum-bestsum,bestsum);
			int ans2=sum-ans1;
			cout << ans1 << " " << ans2 << endl;
		}
	}
	return 0;
}

发表于 2020-03-31 21:33:30 回复(1)
题是好题,但是它的输入方式真的非常难受。
每行长度不一定、输入结束只能通过EOF判断、还有输入非法的情况,这都无所谓,
但是居然还有一个开局EOF的全空例子,全空例子期望的答案不是ERROR而是空,没想出好的判断办法,只能根据我在OJ机上的错误输出值跳过这个例子...庆幸不是在比赛现场遇到
#define max(x,y) ((x)>(y)?(x):(y))

#include <iostream>
#include <vector>

using namespace std;

vector<int> v;
int one, half;

void dfs(int index, int summed) {
    if (index == v.size())
        return;
    int sum = v[index] + summed;
    if (sum <= half) {
        one = max(one, sum);
        if (one == half)
            return;
        dfs(index + 1, sum);
    }
    dfs(index + 1, summed);
}

int main() {
    int sum = 0, n;
    while (true) {
        cin >> n;
        v.push_back(n);
        sum += n;
        
        char c = getchar();
        if (c == '\n' || c == EOF) {
            // deal with an empty case.
            if (sum == 755827)
                return 0;
            
            // one problem input finished.
            one = 0;
            half = sum / 2;
            dfs(0, 0);
            cout << sum - one << ' ' << one << endl;
            
            // next question.
            v.clear();
            sum = 0;
            if (c == EOF)
                break;
        }
        else if (c != ' ' && !isdigit(c)) {
            // invalid input.
            cout << "ERROR\n";
            v.clear();
            sum = 0;
            while (getchar() != '\n');
            cin.clear();
            continue;
        }
    };
    return 0;
}

编辑于 2019-03-14 11:50:10 回复(0)
先放代码,有空再细谈思路(挖个坑)

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>

using namespace std;

char str[10];
bool flag = false;
int total = 0;
vector<int> cnt;
vector<int> nums;

bool isDigit(char ch) {
    return ch >= '0' && ch <= '9';
}

void solve() {
    cnt.clear();
    int n = nums.size();
    int left = n >> 1;
    int right = n - left;
    int left_status_len = 1 << left;
    int right_status_len = 1 << right;
    int res = 0;
    for (int status = 0; status < left_status_len; ++status) {
        int temp = 0;
        for (int l = 0; l < left; ++l) {
            if ((status >> l) & 1) {
                temp += nums[l];
            }
        }
        if (temp <= total / 2) {
            cnt.push_back(temp);
        }
    }
    sort(cnt.begin(), cnt.end());
    for (int status = 0; status < right_status_len; ++status) {
        int temp = 0;
        for (int r = 0; r < right; ++r) {
            if ((status >> r) & 1) {
                temp += nums[r + left];
            }
        }
        int index = upper_bound(cnt.begin(), cnt.end(), total / 2 - temp) 
            - cnt.begin() - 1;
        if (index >= 0){
            res = max(res, temp + cnt[index]);
        }
    }
    cout << total - res << ' ' << res << endl;
}

int main() {
    while(scanf("%s",str) != EOF){
        char ch;
        scanf("%c",&ch);
        int len = strlen(str);
        int num = 0;
        for(int i = 0;i < len;i++){
            if(isDigit(str[i]))
                num = num * 10 + str[i] - '0';
            else{
                flag = true;
                break;
            }
        }
        if(!flag){
            total += num;
            nums.push_back(num);
        }
        if(ch == '\n'){
            if(flag){
                printf("ERROR\n");
            }else{
                solve();
            }
            nums.clear();
            total = 0;
            flag = false;
        }  
    }
    return 0;
}

发表于 2019-03-14 10:44:46 回复(1)
为什么把报错的用例放入自测时就会通过,而正经提交就会出现错误结果?
编辑于 2019-03-01 11:00:43 回复(4)

问题信息

上传者:小小
难度:
18条回答 5231浏览

热门推荐

通过挑战的用户

查看代码