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{玄学}))

  • 相关阅读:
    解决 搭建Jekins过程中 启动Tomcat的java.net.UnknownHostException异常
    射手和农场主
    java 和 JS(javaScript)中的反斜杠正则转义
    分享修改密码的SharePoint Web part: ITaCS Change Password web part
    分享微软官方Demo用的SharePoint 2010, Exchange 2010, Lync 2010虚拟机
    Office 365 的公共网站的一些限制及解决的办法
    SharePoint 2013 关闭 customErrors
    安装 KB2844286 导致SharePoint 2010 XSLT web part 显示出现错误
    安装Office Web Apps Server 2013 – KB2592525安装失败
    如何将hyper-v虚拟机转换成vmware的虚拟机- 转换SharePoint 2010 Information Worker Demonstration and Evaluation Virtual Machine (SP1)
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/14876327.html
Copyright © 2011-2022 走看看