• 2018 Multi-University Training Contest 3 1003 / hdu6321 Problem C. Dynamic Graph Matching 状压dp


    Problem C. Dynamic Graph Matching

    题意:
    给定一个n个点的无向图,m次加边或者删边操作。在每次操作后统计有多少个匹配包含k= 1,2,...,n2条边。
    2≤n≤10,1≤m≤30000。 Shortest judge solution: 770 bytes
    题解:
    设f[i][S]表示前i次操作之后,S集合的点已经匹配的方案数。
    对于加边操作,显然f[i][S] =f[i−1][S] +f[i−1][S−u−v]。i这一维可以省略,从大到小遍历S,f[S]+ =[S−u−v]。
    对于删边操作,注意到加边操作的顺序不影响结果,可以假设第i−1次操作是加入要删除的边。
    将加边操作的更新倒过来,得到:从小到大遍历S,f[S]−=f[S−u−v]。
    时间复杂度O(m2n)。

    遍历顺序应该没有影响,因为 S 与 S-u-v 集合没有交集。

    
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a; i<=b; ++i)
    #define per(i,b,a) for (int i=b; i>=a; --i)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    #define MP make_pair
    #define PB push_back
    #define fi  first
    #define se  second
    typedef long long ll;
    const int N = 200005, mod = 1e9+7;
    
    int cnt_1(int x) {
        int ret=0; for(int j=0; j<=9; ++j) if((x>>j)&1) ++ret; return ret;
    }
    int n, m, cnt1[3000];
    ll  ans[15], dp[3000];
    int main()
    {
        for(int i=0; i<(1<<10); ++i) cnt1[i] = cnt_1(i);
        int T;  scanf("%d", &T);
        while(T--)
        {
            mes(ans, 0);  mes(dp, 0);  dp[0]=1;
            scanf("%d%d", &n, &m);
            char ch;   int u, v;
            while(m--)
            {
                scanf("%*c%c%d%d", &ch, &u, &v);
                --u,  --v;
                int edge = (1<<u)|(1<<v);
                if(ch=='+') {
                    for(int i=(1<<n)-1; i>=0; --i)
                        if(cnt1[i&edge] == 2)
                            dp[i] = (dp[i]+dp[i-edge]+mod) %mod;
                }
                else {
                    for(int i=0; i<(1<<n); ++i)
                        if(cnt1[i&edge] == 2)
                            dp[i] = (dp[i]-dp[i-edge]+mod) %mod;
                }
                rep(i,0,14)  ans[i] = 0;
                for(int i=0; i<(1<<n); ++i)
                    ans[cnt1[i]] = (ans[cnt1[i]]+dp[i]+mod) %mod;
                for(int i=2; i<=n; i+=2)
                    printf("%lld%c", ans[i], " 
    "[i==n]);
            }
        }
    
        return 0;
    }
    
  • 相关阅读:
    (杭电 1014)Uniform Generator
    错排公式浅谈(推导+应用)
    (杭电 2045)不容易系列之(3)—— LELE的RPG难题
    (杭电 2046)骨牌铺方格
    (补题 杭电 2044)一只小蜜蜂...
    (杭电 1097)A hard puzzle
    Linux内核实验作业六
    《Linux内核设计与实现》第十八章读书笔记
    实验作业:使gdb跟踪分析一个系统调用内核函数
    k8s标签
  • 原文地址:https://www.cnblogs.com/sbfhy/p/9410435.html
Copyright © 2020-2023  润新知