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

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 of 1 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 form x+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', where x indicates the case number and counts from 1 and y is the result.
 

Sample Input
  
  
3 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 0 3 3 0 3 0 0 0 0
 

Sample Output
  
  
Case #1: 2 Case #2: 6 Case #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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值