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;

}


 

 

 

你可能感兴趣的:(uva)