bzoj4531 [Bjoi2014]路径

Description

 

在一个N个节点的无向图(没有自环、重边)上,每个点都有一个符号,
可能是数字,也可能是加号、减号、乘号、除号、小括号。你要在这个图上数
一数,有多少种走恰好K个节点的方法,使得路过的符号串起来能够得到一
个算数表达式。路径的起点和终点可以任意选择。
所谓算数表达式,就是由运算符连接起来的一系列数字。括号可以插入在
表达式中以表明运算顺序。
注意,你要处理各种情况,比如数字不能有多余的前导0,减号只有前面
没有运算符或数字的时候才可以当成负号,括号可以任意添加(但不能有空括
号),0可以做除数(我们只考虑文法而不考虑语意),加号不能当正号。
例如,下面的是合法的表达式:
-0/0
((0)+(((2*3+4)+(-5)+7))+(-(2*3)*6))
而下面的不是合法的表达式:
001+0
1+2(2)
3+-3
--1
+1
()

Input

第一行三个整数N,M,K,表示点的数量,边的数量和走的节点数。
第二行一个字符串,表示每个点的符号。
接下来M行,每行两个数,表示一条边连的两个点的编号。
1≤N≤20,0≤M≤N×(N-1)/2,0≤K≤30

Output

输出一行一个整数,表示走的方法数。这个数可能比较大,你只需要输出
它模1000000007的余数即可。

dp,状态表示为四维:(第几步,表达式末尾所在的点,未匹配的左括号数,表达式是否以一个0结尾)

#include<cstdio>
int n,m,k;
char s[64];
int es[1000],enx[1000],e0[24],ep=2;
int f[36][36][36][2];
bool o[256],num[256];
bool ed[24][24];
const int P=1e9+7;
inline void add(int&a,int b){
    a=(a+b)%P;
}
int main(){
    scanf("%d%d%d%s",&n,&m,&k,s+1);
    for(int i=0,a,b;i<m;i++){
        scanf("%d%d",&a,&b);
        ed[a][b]=ed[b][a]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++)if(ed[i][j]){
            es[ep]=j;enx[ep]=e0[i];e0[i]=ep++;
            if(i==j)continue;
            es[ep]=i;enx[ep]=e0[j];e0[j]=ep++;
        }
    }
    for(int i='0';i<='9';i++)num[i]=1;
    o['+']=o['-']=o['*']=o['/']=1;
    for(int i=1;i<=n;i++){
        char c=s[i];
        if(c=='(')f[1][i][1][0]=1;
        if(num[c])f[1][i][0][c=='0']=1;
        if(c=='-')f[1][i][0][0]=1;
    }
    for(int t=2;t<=k;t++){
        for(int w=1;w<=n;w++){
            char c1=s[w];
            for(int j=e0[w],u;j;j=enx[j]){
                u=es[j];
                char c2=s[u];
                for(int k=0;k<18;k++){
                    if(c2=='('){
                        if(num[c1]||c1=='-')add(f[t][w][k][c1=='0'],f[t-1][u][k][0]);
                        else if(c1=='(')add(f[t][w][k+1][0],f[t-1][u][k][0]);
                    }else if(c2==')'){
                        if(o[c1])add(f[t][w][k][0],f[t-1][u][k][0]);
                        else if(c1==')'&&k)add(f[t][w][k-1][0],f[t-1][u][k][0]);
                    }else if(o[c2]){
                        if(num[c1])add(f[t][w][k][c1=='0'],f[t-1][u][k][0]);
                        else if(c1=='(')add(f[t][w][k+1][0],f[t-1][u][k][0]);
                    }else if(num[c2]){
                        if(num[c1])add(f[t][w][k][0],f[t-1][u][k][0]);
                        else if(o[c1])add(f[t][w][k][0],f[t-1][u][k][0]),add(f[t][w][k][0],f[t-1][u][k][1]);
                        else if(c1==')'&&k>0)add(f[t][w][k-1][0],f[t-1][u][k][0]),add(f[t][w][k-1][0],f[t-1][u][k][1]);
                    }
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)if(s[i]==')'||num[s[i]])add(ans,f[k][i][0][0]),add(ans,f[k][i][0][1]);
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5397064.html