分数组(思想很重要)

分数组可以认为是枚举子集问题

可以枚举出所有的子集,然后判读这个子集和他的补集是不是最小的哪一个

但是没有必要这么做,因为可以在枚举子集的过程中进行剪枝

下面是代码:代码中有详细的注释,里面有很多东西值得学习

while(cin>>s)

以及在DFS中每一条语句代表什么意义

排序对于枚举子集是很重要的,可以方便剪枝

//分数组,使用回溯法,枚举子集
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
using namespace std;

const int maxn = 100000;
vector<int>V;

//合法则输出对应的正整数,不合法则0
int string_int(string s)
{
    int sum = 0;
    int pos = 0;
    while(pos < s.size())
    {
        if(s[pos] <= '9' && s[pos] >= '0')
        {
            sum = sum * 10 + s[pos] - '0';
        }
        else
            return 0;
        pos++;
    }
    return sum;
}

int ans[maxn];
int best_ans[maxn];
int SUM = 0;
int min_gap;

void print_V()
{
    for(int i = 0;i < V.size();i++)
    {
        printf("%d ",V[i]);
    }
    printf("\n");
}
void print_A(int cur)
{
    for(int i = 0;i < cur;i++)
    {
        printf(" %d ",V[ans[i]]);
    }
    printf("\n");

}



bool DFS(int cur,int sum)//来看这个DFS中每一条语句的作用
{
//print_A(cur);
//首先要明确,做一次选择,就像当于在解答树中添加了一条边。进入一次DFS,就是一个集合
//所以,是否要剪枝,应该在做选择的时候判断,这个当前的这个子集是什么情况需要在DFS一开始来判断


//注意只有枚举子集的解答树的答案可能在遍历的每一个结点上,像八皇后问题那样,可能的答案只能在最后的末端 if(SUM - sum - sum == 0) { min_gap = 0; memcpy(best_ans,ans,sizeof(int) * cur); return true;//找到了一个最优解,可以直接返回,所有的都可以不用再判断 } else if(SUM - sum - sum < min_gap) { min_gap = SUM - sum - sum; memcpy(best_ans,ans,sizeof(int) * cur); } int pos; if(cur == 0) { pos = 0; } else { pos = ans[cur - 1] + 1; } for(;pos < V.size();pos++) { //选择一次就相当于添加了一个分支 if(sum + V[pos] <= SUM / 2) { ans[cur] = pos; if(DFS(cur + 1,sum + V[pos]))//如果已经挑到了相等的,那么直接返回就可以了,如果递归后的地方有返回true的,那么在这个地方直接返回就可以了 return true; } else { return false;//因为后面的肯定比这个要大,所以选后面的没有意义 } } return false; } int main() { freopen("input.txt","r",stdin); //scanf("%d",&x); string s; //cin>>s; int ok = 1; while(cin >> s)//重要 { int x = string_int(s); if(!x) { ok = 0; printf("EERROR\n"); break; } else { SUM = SUM + x; V.push_back(x); } } sort(V.begin(),V.end()); //print_V(); min_gap = SUM; if(ok) { DFS(0,0); printf("%d %d",(SUM - min_gap) / 2,SUM - (SUM - min_gap) / 2 ); } return 0; }

 

转载于:https://www.cnblogs.com/TorettoRui/p/10517208.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值