打表法——暴力破解方法之一

发布于 2020-02-23  260 次阅读


打表常见的做法

  • 在程序中一次性计算出所有用到的结果,之后的查询直接取这些结果。(最常用)

  • 在程序B中分一次或多次计算出所有需要用到的结果,手动把结果写在程序A的数组中,然后在程序A中就可以直接使用这些结果。

使用场景:从程序的一部分过程的消耗时间过多,或是没有想到好的算法,因此可以在另外一个程序中使用暴力算法求出结果。

  • 对一些不会做的题目,先用暴力程序计算小范围数据的结果,然后找规律,或许能找出答案。

使用场景:在数据范围大时容易用到。

例题

P1149 火柴棒等式

例一:P1149 火柴棒等式

这道题n<=20完全可以打表,使用打表法中的第一个方法。
代码(生成答案):

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main(){
    freopen("ans.txt","w",stdout);
    int a[10]={6,2,5,5,4,5,6,3,7,6};
    int i,j,temp=0,num=0,k,in[2020],n;
    in[0]=6;
    for(i=1;i<=2000;i++){
        k=i;
        temp=0;
        while(k){
            temp+=a[k%10];
            k/=10;
        }
        in[i]=temp;
    }
    n=0;
    Again:
    num=0;
    for(i=0;i<=999;i++){
        for(j=0;j<=999;j++){
            if(n==in[i]+in[j]+in[i+j]+4) num++;
        }
    }
    printf("%d,",num);
    if(n<24){n++;goto Again;}
    return 0;
}

提交代码:

#include<iostream>
using namespace std;
int ans[]={0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,8,9,6,9,29,39,38,65,88,128};
int n;
int main(){
    cin>>n;
    cout<<ans[n]<<'\n';
    return 0;
}

例二:骨牌问题[3]
Description

  在《骨牌问题[版本1]》中问题描述为:“有 2 行 n 列的长方形,用 n 个 12 的骨牌铺满,请计算有多少种铺法。”我们知道这个问题可用递推算法来解决,递推方程如下:
   d[1]=1;
   d[2]=2;
   d[n]=d[n-1]+d[n-2] (n>2)
  现在我们把这个问题推广一下:“有 m 行 n 列的长方形,用 (m
n)/2 个 1*2 的骨牌铺满,请计算有多少种铺法。

Input

若干行,每行包含两个整数:m,n,表示长方形的行和列的数量。

Output

若干行,每行一个整数,对应输入中的长方形铺满的方案数。

Sample Input 1

    1 2
    1 3
    1 4
    2 2
    2 3
    2 4
    2 11
    4 11

Sample Output 1

    1
    0
    1
    2
    3
    5
    144
    51205

Hint

m*n<=121

由于目前主要目的是讲打表法,此题解法不重点说明,反正正解是用的状压DP

这道题m*n<=121完全可以用打表的方法,先状压DP生成表:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,ALL;
ll d[121][2058];
int A,B;
void shift(int i,int j,int A_){
    if(j>n-1){
        d[i][B]=d[i][B]+d[i-1][A_];
        return;
    }
    if(A_&(1<<j)){
        B=B&(~(1<<j)); shift(i,j+1,A_);
    }
    if(j<n-1&&(A_&(1<<j))&&(A_&(1<<(j+1)))){
        B|=(1<<j);B|=(1<<(j+1));shift(i,j+2,A_);
    }
    if(!(A&(1<<j))){
        B|=(1<<j);shift(i,j+1,A_);
    }
}
void dp(){
    if(n>m) swap(n,m);
    ALL=(1<<n)-1;
    memset(d,0,sizeof(d));
    d[0][ALL]=1;
    for(int i=0;i<m;i++)
    for(A=0;A<=ALL;A++){
        B=0;
        shift(i+1,0,A);
    }
}
int main(){
    freopen("ans.txt","w",stdout);//输出到答案表中 
    int cnt=0;
    printf("\t");
    for(int i=1;i<=121;i++)
    for(int j=1;i*j<=121;j++) if(i*j%2==0&&i<=j){//枚举情况 
        n=i;m=j;
        dp();//状压DP 
        cnt++;
        printf("f[%d][%d]=%lldLL",i,j,d[m][ALL]);
        printf("%s",cnt%3?",":";\n\t");//格式控制 
    }
    return 0;
}

然后把答案copy到程序中就可以了:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll f[20][150];
int x,y;
void get_V(){
    f[1][2]=1LL,f[1][4]=1LL,f[1][6]=1LL;
    f[1][8]=1LL,f[1][10]=1LL,f[1][12]=1LL;
    f[1][14]=1LL,f[1][16]=1LL,f[1][18]=1LL;
    f[1][20]=1LL,f[1][22]=1LL,f[1][24]=1LL;
    f[1][26]=1LL,f[1][28]=1LL,f[1][30]=1LL;
    f[1][32]=1LL,f[1][34]=1LL,f[1][36]=1LL;
    f[1][38]=1LL,f[1][40]=1LL,f[1][42]=1LL;
    f[1][44]=1LL,f[1][46]=1LL,f[1][48]=1LL;
    f[1][50]=1LL,f[1][52]=1LL,f[1][54]=1LL;
    f[1][56]=1LL,f[1][58]=1LL,f[1][60]=1LL;
    f[1][62]=1LL,f[1][64]=1LL,f[1][66]=1LL;
    f[1][68]=1LL,f[1][70]=1LL,f[1][72]=1LL;
    f[1][74]=1LL,f[1][76]=1LL,f[1][78]=1LL;
    f[1][80]=1LL,f[1][82]=1LL,f[1][84]=1LL;
    f[1][86]=1LL,f[1][88]=1LL,f[1][90]=1LL;
    f[1][92]=1LL,f[1][94]=1LL,f[1][96]=1LL;
    f[1][98]=1LL,f[1][100]=1LL,f[1][102]=1LL;
    f[1][104]=1LL,f[1][106]=1LL,f[1][108]=1LL;
    f[1][110]=1LL,f[1][112]=1LL,f[1][114]=1LL;
    f[1][116]=1LL,f[1][118]=1LL,f[1][120]=1LL;
    f[2][2]=2LL,f[2][3]=3LL,f[2][4]=5LL;
    f[2][5]=8LL,f[2][6]=13LL,f[2][7]=21LL;
    f[2][8]=34LL,f[2][9]=55LL,f[2][10]=89LL;
    f[2][11]=144LL,f[2][12]=233LL,f[2][13]=377LL;
    f[2][14]=610LL,f[2][15]=987LL,f[2][16]=1597LL;
    f[2][17]=2584LL,f[2][18]=4181LL,f[2][19]=6765LL;
    f[2][20]=10946LL,f[2][21]=17711LL,f[2][22]=28657LL;
    f[2][23]=46368LL,f[2][24]=75025LL,f[2][25]=121393LL;
    f[2][26]=196418LL,f[2][27]=317811LL,f[2][28]=514229LL;
    f[2][29]=832040LL,f[2][30]=1346269LL,f[2][31]=2178309LL;
    f[2][32]=3524578LL,f[2][33]=5702887LL,f[2][34]=9227465LL;
    f[2][35]=14930352LL,f[2][36]=24157817LL,f[2][37]=39088169LL;
    f[2][38]=63245986LL,f[2][39]=102334155LL,f[2][40]=165580141LL;
    f[2][41]=267914296LL,f[2][42]=433494437LL,f[2][43]=701408733LL;
    f[2][44]=1134903170LL,f[2][45]=1836311903LL,f[2][46]=2971215073LL;
    f[2][47]=4807526976LL,f[2][48]=7778742049LL,f[2][49]=12586269025LL;
    f[2][50]=20365011074LL,f[2][51]=32951280099LL,f[2][52]=53316291173LL;
    f[2][53]=86267571272LL,f[2][54]=139583862445LL,f[2][55]=225851433717LL;
    f[2][56]=365435296162LL,f[2][57]=591286729879LL,f[2][58]=956722026041LL;
    f[2][59]=1548008755920LL,f[2][60]=2504730781961LL,f[3][4]=11LL;
    f[3][6]=41LL,f[3][8]=153LL,f[3][10]=571LL;
    f[3][12]=2131LL,f[3][14]=7953LL,f[3][16]=29681LL;
    f[3][18]=110771LL,f[3][20]=413403LL,f[3][22]=1542841LL;
    f[3][24]=5757961LL,f[3][26]=21489003LL,f[3][28]=80198051LL;
    f[3][30]=299303201LL,f[3][32]=1117014753LL,f[3][34]=4168755811LL;
    f[3][36]=15558008491LL,f[3][38]=58063278153LL,f[3][40]=216695104121LL;
    f[4][4]=36LL,f[4][5]=95LL,f[4][6]=281LL;
    f[4][7]=781LL,f[4][8]=2245LL,f[4][9]=6336LL;
    f[4][10]=18061LL,f[4][11]=51205LL,f[4][12]=145601LL;
    f[4][13]=413351LL,f[4][14]=1174500LL,f[4][15]=3335651LL;
    f[4][16]=9475901LL,f[4][17]=26915305LL,f[4][18]=76455961LL;
    f[4][19]=217172736LL,f[4][20]=616891945LL,f[4][21]=1752296281LL;
    f[4][22]=4977472781LL,f[4][23]=14138673395LL,f[4][24]=40161441636LL;
    f[4][25]=114079985111LL,f[4][26]=324048393905LL,f[4][27]=920471087701LL;
    f[4][28]=2614631600701LL,f[4][29]=7426955448000LL,f[4][30]=21096536145301LL;
    f[5][6]=1183LL,f[5][8]=14824LL,f[5][10]=185921LL;
    f[5][12]=2332097LL,f[5][14]=29253160LL,f[5][16]=366944287LL;
    f[5][18]=4602858719LL,f[5][20]=57737128904LL,f[5][22]=724240365697LL;
    f[5][24]=9084693297025LL,f[6][6]=6728LL,f[6][7]=31529LL;
    f[6][8]=167089LL,f[6][9]=817991LL,f[6][10]=4213133LL;
    f[6][11]=21001799LL,f[6][12]=106912793LL,f[6][13]=536948224LL;
    f[6][14]=2720246633LL,f[6][15]=13704300553LL,f[6][16]=69289288909LL;
    f[6][17]=349519610713LL,f[6][18]=1765722581057LL,f[6][19]=8911652846951LL;
    f[6][20]=45005025662792LL,f[7][8]=1292697LL,f[7][10]=53175517LL;
    f[7][12]=2188978117LL,f[7][14]=90124167441LL,f[7][16]=3710708201969LL;
    f[8][8]=12988816LL,f[8][9]=108435745LL,f[8][10]=1031151241LL;
    f[8][11]=8940739824LL,f[8][12]=82741005829LL,f[8][13]=731164253833LL;
    f[8][14]=6675498237130LL,f[8][15]=59554200469113LL,f[9][10]=14479521761LL;
    f[9][12]=1937528668711LL,f[10][10]=258584046368LL,f[10][11]=3852472573499LL;
    f[10][12]=65743732590821LL;
}
int main(){
    get_V();
    while(scanf("%d%d",&x,&y)==2){
        if(x>y) swap(x,y);
        printf("%lld\n",f[x][y]);
    }
    return 0;
}

值得注意的是,long long赋值的时候建议加上LL后缀

还有,当m*n为奇数是由于全局变量默认为0,正好输出0

列举一些常用的表:

1.素数表

2.阶乘表

3.逆元表

当然打表并不一定要直接初始化,也可以通过线性筛/递推打出。

参考

信息竞赛--打表法讲解
暴力&打表

本文标题:《打表法——暴力破解方法之一》

本文链接:https://wnag.com.cn/922.html

特别声明:除特别标注,本站文章均为原创,本站文章原则上禁止转载,如确实要转载,请电联:wangyeuuu@qq.com,尊重他人劳动成果,谢过~


正因为有要好好实现的梦想,所以今天也要好好加油。