zoukankan      html  css  js  c++  java
  • NOIP 模拟 $20; m y$

    题解 (by;zjvarphi)

    首先发现一共最多只有 (2^d) 种道路,那么可以状压,(不要 (dfs),会搜索过多无用的状态)

    那么设 (f_{i,j,k}) 为走 (i) 步,走到 (j),状态为 (k) 是否可行,那么转移就是 (mathcal O m (n^22^n)),过不了

    有一种技巧,叫 ( m meet;in;the;middle),从中间折半,设 (f_{i,j,k}) 表示由 (1) 出发,走 (i) 步到 (j),状态为 (k) 是否可行

    (g_{i,j,k}) 表示以任意一个点为起点,其余同上

    那么最终只要将两种状态拼起来即可,复杂度是 (mathcal O m (n^2*2^frac{n}{2}+2^n))

    注意,需要判断奇数折半的情况

    Code
    #include<bits/stdc++.h>
    #define ri register signed
    #define p(i) ++i
    using namespace std;
    namespace IO{
        char buf[1<<21],*p1=buf,*p2=buf;
        #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
        template<typename T>inline void read(T &x) {
            ri f=1;x=0;register char ch=gc();
            while(ch<'0'||ch>'9') {if (ch=='-') f=0;ch=gc();}
            while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
            x=f?x:-x;
        }
    }
    using IO::read;
    namespace nanfeng{
        #define pb(x) push_back(x)  
        #define FI FILE *IN
        #define FO FILE *OUT
        template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
        template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
        static const int N=92;
        bitset<1<<11> bit[12][N],bt[N];
        bitset<2> eg[N][N];
        int first[N],vis[1<<21],n,m,d,t=1,hd,ans;
        struct edge{int v,nxt,c;}e[N*N<<1];
        vector<int> sta[N],st2[N];
        inline void add(int u,int v,int c) {
            e[t].v=v,e[t].c=c,e[t].nxt=first[u],first[u]=t++;
            e[t].v=u,e[t].c=c,e[t].nxt=first[v],first[v]=t++;
        }
        inline int main() {
            // FI=freopen("nanfeng.in","r",stdin);
            // FO=freopen("nanfeng.out","w",stdout);
            read(n),read(m),read(d);
            hd=d>>1;
            for (ri i(1),u,v,c;i<=m;p(i)) {
                read(u),read(v),read(c);
                if (eg[u][v][c]) continue;
                eg[u][v][c]=eg[v][u][c]=1;
                add(u,v,c);
            }
            bit[0][1][0]=1;
            for (ri i(0);i<hd;p(i)) {
                int S=(1<<i)-1;
                for (ri j(0);j<=S;p(j)) 
                    for (ri k(1);k<=n;p(k)) {
                        if (!bit[i][k][j]) continue;
                        for (ri ed(first[k]);ed;ed=e[ed].nxt) { 
                            ri cst=j<<1|e[ed].c;
                            bit[i+1][e[ed].v][cst]=1;
                            if (i+1==hd&&!bt[e[ed].v][cst]) 
                                sta[e[ed].v].pb(cst),bt[e[ed].v][cst]=1;
                        }
                    }
            }
            for (ri i(0);i<=11;p(i)) 
                for (ri j(0);j<N;p(j)) bit[i][j].reset();
            for (ri i(1);i<=N;p(i)) bt[i].reset();
            if (d&1) p(hd);
            for (ri i(1);i<=n;p(i)) bit[0][i][0]=1;
            for (ri i(0);i<hd;p(i)) {
                int S=(1<<i)-1;
                for (ri j(0);j<=S;p(j)) 
                    for (ri k(1);k<=n;p(k)) {
                        if (!bit[i][k][j]) continue;
                        for (ri ed(first[k]);ed;ed=e[ed].nxt) { 
                            ri cst=j<<1|e[ed].c;
                            bit[i+1][e[ed].v][cst]=1;
                            if (i+1==hd&&!bt[e[ed].v][cst]) 
                                st2[e[ed].v].pb(cst),bt[e[ed].v][cst]=1;
                        }
                    }
            } 
            for (ri i(1);i<=n;p(i)) {
                ri siz=sta[i].size(),sz=st2[i].size();
                for (ri j(0);j<siz;p(j)) {
                    ri tst=sta[i][j]<<hd;
                    for (ri k(0);k<sz;p(k)) {
                        ri stt=tst|st2[i][k];
                        if (!vis[stt]) p(ans),vis[stt]=1;  
                        if (ans==(1<<d)) break;
                    }
                    if (ans==(1<<d)) break;
                }
                if (ans==(1<<d)) break;
            }
            printf("%d
    ",ans);
            return 0;
        }  
    }
    int main() {return nanfeng::main();} 
    
  • 相关阅读:
    HDU 3605 Escape 最大流
    HDU 3416 Marriage Match IV (最短路径&&最大流)
    洛谷1508 简单记忆化搜索
    洛谷1880 区间dp+记忆化搜索 合并石子
    洛谷1063 +区间dp(经典问题)
    洛谷1074 靶状数独dfs 排序、记录、搜索
    hdu3368 dfs 下棋
    hdu1258 dfs 给一个指定的target数和一个数列,要求不重复选择其中的数使得和为target并打印,结果不可重复。
    hdu1181 dfs 字符串首尾可拼接,问是否可寻找到一条字串路径使得首尾分别是‘b’和‘m’,简单的搜索+回溯
    hdu1078 dfs+dp(记忆化搜索)搜索一条递增路径,路径和最大,起点是(0,0)
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/15042650.html
Copyright © 2011-2022 走看看