zoukankan      html  css  js  c++  java
  • luogu 3959 宝藏

    noip2017 D2T2 宝藏 某zz选手看到数据范围直接就dfs了,骗到了70分

    题目大意:

    n宝藏屋,已知n 个宝藏屋之间可供开发的 m 条道路和它们的长度

    选择一个宝藏屋作为起点

    新开发一条道路的代价是:L×K

    L代表这条道路的长度,K代表从起点宝藏屋到这条道路起点的宝藏屋所经过的宝藏屋的数量(包括起点宝藏屋和这条道路起点的宝藏屋) 

    选定起点宝藏屋和之后开凿的道路,使得工程总代价最小,并输出这个最小值

    思路:

    看到n为12本来想到状压dp的,但是以为dfs剪枝能过(大佬们的dfs可以过)

    然后就是状态dp[i][j] 其中i表示所有点的最大深度,j表示联通状态

    对于每个状态可以枚举j的补集的子集,然后枚举点把他们连起来

    转移就行了

    具体见注释

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #define inf 2139062143
    10 #define ll long long
    11 #define MAXN 10010000
    12 #define MOD
    13 using namespace std;
    14 inline int read()
    15 {
    16     int x=0,f=1;char ch=getchar();
    17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    19     return x*f;
    20 }
    21 int n,m,map[15][15],dp[15][4500],l[4500];
    22 int lowbit(int x) {return x&(-x);}
    23 int main()
    24 {
    25     n=read(),m=read();int a,b,c,t=(1<<n)-1,rst,tmp,v;
    26     memset(dp,127,sizeof(dp));
    27     for(int i=0;i<n;i++) dp[0][1<<i]=0,l[1<<i]=i;//初始化以每一个点作为起点的状态 
    28     memset(map,127,sizeof(map));
    29     while(m--)
    30     {
    31         a=read()-1,b=read()-1,c=read();
    32         map[b][a]=map[a][b]=min(map[a][b],c);
    33     }
    34     for(int i=0;i<n;i++)
    35         for(int j=0;j<=t;j++)
    36         {
    37             if(dp[i][j]==inf) continue;
    38             rst=t^j;//rst为当前集合的补集 
    39             for(int k=rst;k;k=(k-1)&rst)//枚举补集的子集(一个枚举子集的骚操作,具体操作可以脑补) 
    40             {
    41                 tmp=0;
    42                 for(int a=k;a;a-=lowbit(a))//枚举 k(补集的子集 )里的每一个点 
    43                 {
    44                     v=inf;
    45                     //枚举 j(当前连通块)内的所有点与 k内这个点相连的最小值 
    46                     for(int b=j;b;b-=lowbit(b)) v=min(v,map[l[lowbit(a)]][l[lowbit(b)]]);
    47                     if(v==inf) break;//如果找不到,说明无法转移到 j|k 这个状态 
    48                     tmp+=v;
    49                 }
    50                 if(v==inf) continue;//这个子集不合法 
    51                 tmp*=(i+1);
    52                 dp[i+1][j|k]=min(dp[i+1][j|k],dp[i][j]+tmp);//把 k和 j连了起来,所以连通块状态为 j|k 
    53             }
    54         }
    55     int ans=inf;
    56     for(int i=0;i<n;i++) ans=min(ans,dp[i][t]);//枚举把所有点都连起来的不同深度 
    57     printf("%d",ans);
    58 }
    View Code
  • 相关阅读:
    堆、栈、值类型、引用类型分析总结 Part 2
    DataGridView打印
    学习使用ArrayList
    C#与Java之比较
    【原创】串口通信测试程序
    彩色校验码的制作
    C#中使用进度条
    【原创】 Ajax之ModalPopup编程实例
    常用正则表达式
    堆、栈、值类型、引用类型分析总结 Part 1
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/7875301.html
Copyright © 2011-2022 走看看