uva 10317 - Equating Equations

题目链接:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=457&page=show_problem&problem=1258

 

1. 先对等式进行移项,假设原来为1 + 2 = 4 - 5 + 6,那么移动之后就变为了 1 + 2 - 4 + 5 + 6 = 0. 并计算出所有数字之和sum,和等式左边中的正数个数plusNum

2. 然后就演变成了“从n个数中选取总和为sum/2的plusNum个数字组成正数部分”,因为如果等式成立,那么所有正数之和与所有负数之和的绝对值一定是相等的。正样的话,对于每个数,要么取,要么不取,复杂度就变为了 2^16

3. 减枝: 1) 每次递归时,如果当前值加上要选的那个数之和大于sum/2,则不选

                 2) 如果所有数字之和为奇数,那么直接no solution。这个优化相当大,直接从1.9s降到了0.08s。不过rank第一的神牛的0.02s真不知道怎么跑出来的 Orz..



 

#include<cstdio>
#include<cstring>

const int maxn = 1000;
char str[10000];
char sigma[maxn];
bool vis[maxn];
int  num[maxn], ans[maxn], n, idx;
int  plus[maxn], leftNum, plusNum, sum;


inline void read(){
	idx = 1;
	sscanf(str, "%d", &num[0]);
	sum = num[0];
    int len = strlen(str);
	for(int i=1; i<len; ++i){
	    if(str[i]=='+' || str[i]=='-' || str[i]=='=') {
		    if(str[i] == '=') 
                leftNum = idx;
		    sigma[idx] = str[i];
		    sscanf(str+i+1, "%d", &num[idx]);
	    	sum += num[idx++];
	    }

	}
    // 把等式全部移到左边后,计算有多少个加号
    plusNum = 1;
    for(int i=1; i<idx; ++i){
        if(i<leftNum && sigma[i] == '+'){ 
            ++plusNum;
        } else if(i>leftNum && sigma[i] == '-') 
            ++plusNum;
    
    }
}

bool dfs(int cur, int pos, int tot){
    if(plusNum-cur > idx-pos)
        return false;
    if(cur == plusNum){
        if(tot*2 == sum) return true;
        return false;

    }
    if(pos<idx && (tot+num[pos])*2 <= sum){
        vis[pos] = true;
        plus[cur] = num[pos];
        if(dfs(cur+1, pos+1, tot+num[pos])) 
            return true;

    }
    vis[pos] = false;
    if(pos<idx && dfs(cur, pos+1, tot))
        return true;
    return false;

}

inline void solve(){
    //注意减枝!如果sum为奇数那么直接输出no solution
    memset(vis, 0, sizeof(vis));
    if((sum&1)==0 && dfs(0, 0, 0)){ 
        int id=1;
        ans[0] = plus[0];
        for(int i=1; i<idx; ++i){
            if(i<leftNum && sigma[i]=='+') {
                ans[i] = plus[id++];
            } else if(i>leftNum && sigma[i]=='-'){
                ans[i] = plus[id++];
            }

        }
        int k=1;
        for(int i=0; i<idx; ++i)if(!vis[i]){
            while(k<leftNum && sigma[k]=='+' && k<idx) ++k;
            while(k>leftNum && sigma[k]=='-' && k<idx) ++k;
            ans[k++] = num[i];

        }
        printf("%d", ans[0]);
        for(int i=1; i<idx; ++i)
             if(i==leftNum) printf(" = %d",ans[i]);
             else printf(" %c %d", sigma[i], ans[i]);
        puts("");

    }else{
        puts("no solution");
    
    }

}

int main(){

    while(gets(str)){
        read();
        solve();
    }

    return 0;
}


 

 

 

posted @ 2013-03-24 12:09  javawebsoa  Views(158)  Comments(0Edit  收藏  举报