Loading

NOIP 模拟 $20\; \rm y$

题解 \(by\;zj\varphi\)

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

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

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

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

那么最终只要将两种状态拼起来即可,复杂度是 \(\mathcal O\rm (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\n",ans);
        return 0;
    }  
}
int main() {return nanfeng::main();} 
posted @ 2021-07-22 09:35  ナンカエデ  阅读(26)  评论(0编辑  收藏  举报