zoukankan      html  css  js  c++  java
  • NOIP 模拟 6 宝藏

    题目

    题解

    这道题是 (NOIP;;2017) 的原题 ,让我见识到了什么是真正的 (dfs)

    考场上想出来要状压了,(n) 那么小,肯定是压 (n) 那一位,然后层第转移,但是想了半天,一堆细节没搞懂,拿了个暴力分跑了。

    后来看了题解才知道这竟然可以 (dfs) 搜索,虽然说剪支很恶心,但是那 (70) 短小的暴力太

    对于此题,由于我们更新某一条边不仅和终点有关,也和起点有关,所以我们在枚举终点时也要枚举它是有哪个点转移而来的

    (70)(CODE:)

    Code
    #include<bits/stdc++.h>
    #define ri register int
    #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++
        inline int read() {
            ri x=0,f=1;char ch=gc();
            while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
            while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
            return x*f; 
        }
    }
    using IO::read;
    namespace nanfeng{
        #define cmax(x,y) ((x)>(y)?(x):(y))
        #define cmin(x,y) ((x)>(y)?(y):(x))
        #define FI FILE *IN
        #define FO FILE *OUT
        static const int N=14,INF=1e9+7;
        int G[N][N],visn[N],n,m,ans=INT_MAX,tmp;
        void dfs(int x) {
            if (x==n) {ans=cmin(ans,tmp);return;}
            if (tmp>ans) return;//小小的优化
            for (ri i(1);i<=n;p(i)) {//要更新i
                if (visn[i]) continue;
                for (ri j(1);j<=n;p(j)) {//从j转移而来
                    if (!visn[j]||G[j][i]>INF||i==j) continue;
                    tmp+=visn[j]*G[j][i];visn[i]=visn[j]+1;
                    dfs(x+1);
                    tmp-=visn[j]*G[j][i];visn[i]=0;//回溯
                }
            }
        }
        inline int main() {
            // FI=freopen("nanfeng.in","r",stdin);
            // FO=freopen("nanfeng.out","w",stdout);
            n=read(),m=read();
            memset(G,127,sizeof(G));//初值要赋成最大
            for (ri i(1);i<=m;p(i)) {
                int u=read(),v=read(),w=read();
                G[u][v]=G[v][u]=cmin(G[u][v],w);
            } 
            for (ri i(1);i<=n;p(i)) visn[i]=1,dfs(1),visn[i]=0;//记得根也要回溯
            printf("%d
    ",ans);
            return 0;
        }
    }
    int main() {return nanfeng::main();}
    
    这就是 $70$ 分代码,那么往下想,$dfs$ 最大优化手段是什么:剪枝。

    好了我们考虑剪枝

    首先我们最容易想到的就是最优性剪枝,就像是一个估价函数,很好想

    然后我们发现,每一个点它至少需要扩展一条边,所以我们可以对每个点的所有的出边进行由小到大排序

    且题目中说了“两个已经被挖掘过的宝藏屋之间的道路无需再开发”,所以我们可以放心大胆得把每一种情况更新,不用考虑什么后效性

    (ACkern 0.5emCODE:)

    Code
    #include<bits/stdc++.h>
    #define ri register int
    #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++
        inline int read() {
            ri x=0,f=1;char ch=gc();
            while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
            while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
            return x*f; 
        }
    }
    using IO::read;
    namespace nanfeng{
        #define cmax(x,y) ((x)>(y)?(x):(y))
        #define cmin(x,y) ((x)>(y)?(y):(x))
        #define FI FILE *IN
        #define FO FILE *OUT
        #undef bool
        static const int N=14,INF=1e9+7;
        int G[N][N],visn[N],d[N],out[N][N],viso[N],tot,cnt,n,m,ans=INT_MAX,tmp,p;
        inline bool cmp(int x,int y) {return G[p][x]<G[p][y];}
        void dfs(int num,int x) {
            for (ri i(num);i<=cnt;p(i)) {
                if (tot+tmp*visn[viso[i]]>=ans) return;//如果答案直接小于估价值,直接此方案不合法
                for (ri j(x);j<=d[viso[i]];p(j)) {//要从我们的最优开始搜
                    if (visn[out[viso[i]][j]]) continue;//搜过的点不搜
                    viso[p(cnt)]=out[viso[i]][j];
                    tmp-=G[viso[cnt]][out[viso[cnt]][1]];
                    tot+=visn[viso[i]]*G[viso[i]][viso[cnt]];
                    visn[viso[cnt]]=visn[viso[i]]+1;
                    dfs(i,j+1);//我们要从j+1继续搜,因为前面的已经搜过了
                    tmp+=G[viso[cnt]][out[viso[cnt]][1]];
                    tot-=visn[viso[i]]*G[viso[i]][viso[cnt]];
                    visn[viso[cnt--]]=0;//回溯
                }
                x=1;//x要初始为一,因为更换初始点时,他的出边也要从一开始
            }
            if (cnt==n) {ans=cmin(ans,tot);return;}
        }
        inline int main() {
            // FI=freopen("nanfeng.in","r",stdin);
            // FO=freopen("nanfeng.out","w",stdout);
            n=read(),m=read();
            memset(G,127,sizeof(G));
            for (ri i(1);i<=m;p(i)) {
                int u=read(),v=read(),w=read();
                if (G[u][v]<w) continue;
                if (G[u][v]>INF) out[out[u][p(d[u])]=v][p(d[v])]=u;//只有一条边第一次输入时才能加上
                G[u][v]=G[v][u]=w;
            }
            for (ri i(1);i<=n;p(i)) {
                p=i;
                sort(out[i]+1,out[i]+d[i]+1,cmp);//排序
                tmp+=G[i][out[i][1]];
            }
            for (ri i(1);i<=n;p(i)) {
                tot=0;//估价值
                viso[cnt=visn[i]=1]=i;//记录一下选的点
                tmp-=G[i][out[i][1]];//把根节点的最有性减去
                visn[i]=1;
                dfs(1,1);
                visn[i]=0;
                tmp+=G[i][out[i][1]];//回溯
            }
            printf("%d
    ",ans);
            return 0;
        }
    }
    int main() {return nanfeng::main();}
    

    复杂度 (mathcal O(n!/ ext{玄学}))

  • 相关阅读:
    java 实现N进制转M进制
    BigInteger构造函数解析
    SpringBoot 实现前后端分离的跨域访问(CORS)
    python:[numpy] ndarray 与 list 互相转换
    PyTorch使用GPU的方法
    Matplotlib.pyplot 把画图保存为图片 指定图片大小
    python列表中的所有值转换为字符串,以及列表拼接成一个字符串
    python 读取中文文件名/中文路径
    在Python中使用LSTM和PyTorch进行时间序列预测(深度学习时序数据预测)
    记录分析python程序运行时间的几种方法
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/14876327.html
Copyright © 2011-2022 走看看