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; }