HDU-5937 Equation(暴力DFS+剪枝)

来源:互联网 发布:美国7月非农数据 编辑:程序博客网 时间:2024/06/07 11:34

Equation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 543    Accepted Submission(s): 156


Problem Description
Little Ruins is a studious boy, recently he learned addition operation! He was rewarded some number bricks of1 to 9 and infinity bricks of addition mark '+' and equal mark '='.

Now little Ruins is puzzled by those bricks because he wants to put those bricks into as many different addition equations formx+y=z as possible. Each brick can be used at most once and x, y, z are one digit integer.

As Ruins is a beginer of addition operation, x,y and z will be single digit number.

Two addition equations are different if any number of x,y and z is different.

Please help little Ruins to calculate the maximum number of different addition equations.
 

Input
First line contains an integer T, which indicates the number of test cases.

Every test case contains one line with nine integers, the ith integer indicates the number of bricks of i.

Limits
1T30
0bricks number of each type100
 

Output
For every test case, you should output 'Case #x: y', wherex indicates the case number and counts from1 andy is the result.
 

Sample Input
31 1 1 1 1 1 1 1 12 2 2 2 2 2 2 2 20 3 3 0 3 0 0 0 0
 

Sample Output
Case #1: 2Case #2: 6Case #3: 2

题意:9个数字,每个数字有X[i]个,问总共能凑成多少个不同的等式A+B=C

(A B C均为1位,A+B=C和B+A=C视为不同等式)


题解:暴力DFS+剪枝
一开始想用网络流写,但怎么也建不出图来,想到金牌题应该不会很简单.....但真的是这么简单
不过一开始我以数为基点,从1~9开始递归,利用状压选取数字组合成方程,结果TLE了,因为每一层
都达到了2^(9-i)的复杂度显然是不行的。

后来换了下思路:
首先打表发现:
①数字i最多被使用17-i次,因此可以将X[i]缩小为17-i
②等式总共只有36个,因为A+B=C和B+A=C视为不同等式,
因此将它视为1个方程并计算2次即可,这样可以缩小为20个等式

既然方程的个数只有20,那么我们就可以以方程为基点进行递归:
选取第i个方程,假设第i个方程为A+B=C,则A,B,C的数量-1,方程数量+1,再进行递归...

递归剪枝:
设当前有cnt个等式,最大数量有ans个,总共还剩sum个数没用,还剩n个等式没被遍历
①(ans-cnt)*3>=sum时剪掉

②ans-cnt>=n时剪掉

#include<bits/stdc++.h>using namespace std;int op[][3]={{1,1,2},{1,2,3},{1,3,4},{2,2,4},{1,4,5},{2,3,5},{1,5,6},{2,4,6},{3,3,6},{1,6,7},{2,5,7},{3,4,7},{1,7,8},{2,6,8},{3,5,8},{4,4,8},{1,8,9},{2,7,9},{3,6,9},{4,5,9}};int num[]={1,2,2,1,2,2,2,2,1,2,2,2,2,2,2,1,2,2,2,2};int pre[25];int last[]={0,0,0,1,3,5,8,11,15,19};int a[10],ans;void dfs(int cnt,int sum,int n){    ans=max(ans,cnt);    if((ans-cnt)*3>=sum) return;    if(ans-cnt>=pre[n]) return;    for(int i=n;i>=0;i--){        int x=op[i][0],y=op[i][1],z=op[i][2];        a[x]--;a[y]--;a[z]--;        if(a[x]>=0&&a[y]>=0&&a[z]>=0) dfs(cnt+1,sum-3,i-1);        if(num[i]>1){            a[x]--;a[y]--;a[z]--;            if(a[x]>=0&&a[y]>=0&&a[z]>=0) dfs(cnt+2,sum-6,i-1);            a[x]++;a[y]++;a[z]++;        }        a[x]++;a[y]++;a[z]++;    }}int main(){    pre[0]=num[0];    for(int i=1;i<20;i++) pre[i]=pre[i-1]+num[i];    int T;    //freopen("in.txt","r",stdin);    scanf("%d",&T);    for(int cas=1;cas<=T;cas++){        int sum=0;        for(int i=1;i<=9;i++) {            scanf("%d",&a[i]);            if(a[i]>17-i) a[i]=17-i;            sum+=a[i];        }        ans=0;        for(int i=9;i>0;i--) if(a[i]){dfs(0,sum,last[i]);break;}        printf("Case #%d: ",cas);        printf("%d\n",ans);    }    return 0;}


原创粉丝点击