【NOIP2017提高A组模拟9.7】简单无向图 dp

题目

题目大意

现在有一些度数为1,一些度数为2的点,求它们构成图的不同的方案数

tj

设有t1个度数为1的点,t2个度数为2的点,容易发现,答案只与t1,t2的数量有关,那么我们不妨设f[t1][t2]表示现在已经做了t1个1号点,t2个2号点的方案数
转移比较神奇,觉得出题人好**
分为下面的4种情况
1:当t2为0时我们新增若干条长度为2的链,我们将不会在这些链中间加其他任何点
2:新增形如1-2-1的一条新链
3:在条链的一个位置加入两个为2的点
4:把某一条链拆掉,将其中度数为2的点与3个新的点构成一个新的环
这个方法最关键的地方就是它是把一条链中间的度数为2的点和3个新的点构成一个环,很大程度上避免了在环中间加入新的数导致很难搞重复的窘境

贴代码

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define md 998244353
#define ll long long
using namespace std;

const int maxn=2005;

ll f[maxn][maxn];
ll i,j,k,l,m,n,x,y,t1,t2,cs1,cs2;

ll ge(ll x){
    return ((x*(x-1))/2)%md;
}
int main(){
    freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    scanf("%lld",&n);
    fo(i,1,n){
        scanf("%lld",&x);
        if (x==1) cs1++; else cs2++;
    }
    f[0][0]=1;
    fo(t2,0,cs2){
        fo(t1,0,n){
            if (f[t1][t2]==0) continue;
            x=f[t1][t2];
            if (t2==0) f[t1+2][t2]=(f[t1+2][t2]+x*(t1+1))%md;
            f[t1+2][t2+1]=(f[t1+2][t2+1]+x*ge(t1+2))%md;
            f[t1][t2+2]=(f[t1][t2+2]+((x*t1)%md)*(t2+1))%md;
            if (t1>=2) f[t1-2][t2+3]=(f[t1-2][t2+3]+(x*ge(t2+2)))%md;
        }
    }
    printf("%lld",f[cs1][cs2]);
    return 0;
}

你可能感兴趣的:(DP)