【比赛】NOIP2017 宝藏

 

这道题考试的时候就骗了部分分。其实一眼看过去,n范围12,就知道是状压,但是不知道怎么状压,想了5分钟想不出来就枪毙了状压,与AC再见了。

现在写的是状压搜索,其实算是哈希搜索,感觉状压DP理解不了啊。思路来自于Gt,几乎照搬地写了自己的代码。

思路很简单,搜索。搜索里加了个启发,有点,不,是很像最优性剪枝。

dfs里,hsh是每个点的深度哈希起来(初始化要对于每一个点定一个专门的哈希值,用这个值来哈希自己的深度),k是已经连上了多少个点,val是代价。

估价函数里,对于每一个没有加入答案集合的点,找到他连上任意一个集合(可以是答案集合,也可以是以任意一个同样未连上答案集合的点为根的集合,这样的话当前点的深度就为2了)的最小代价。所有代价加起来后就是把剩下所有点加入答案集合的最低要求(不一定是这个值,但一定大于等于这个值),用这个优化dfs。

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 const int MAXN=20,Mod=19260817,inf=0x3f3f3f3f,base=10007;
 5 int n,m,ans,hash[MAXN],f[Mod],G[MAXN][MAXN],d[MAXN];
 6 inline void read(int &x)
 7 {
 8     int data=0,w=1;
 9     char ch=0;
10     while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
11     if(ch=='-')w=-1,ch=getchar();
12     while(ch>='0'&&ch<='9')data=(data<<3)+(data<<1)+(ch^'0'),ch=getchar();
13     x=data*w;
14 }
15 inline void init()
16 {
17     for(register int i=1;i<=n;++i)
18         for(register int j=1;j<=n;++j)G[i][j]=inf;
19     hash[0]=1;
20     for(register int i=1;i<=n;++i)hash[i]=(ll)hash[i-1]*base%Mod;
21     for(register int i=0;i<Mod;++i)f[i]=2e9;
22     ans=2e9;
23 }
24 inline int fr()
25 {
26     int res=0;
27     for(register int i=1;i<=n;++i)
28         if(!d[i])
29         {
30             int tmp=inf;
31             for(register int j=1;j<=n;++j)
32                 if(G[i][j]!=inf)
33                 {
34                     if(d[j])tmp=min(tmp,d[j]*G[i][j]);
35                     else tmp=min(tmp,2*G[i][j]);
36                 }
37             res+=tmp;
38         }
39     return res;
40 }
41 inline void dfs(int k,int val,int hsh)
42 {
43     if(val+fr()>=ans||val>=f[hsh])return ;
44     f[hsh]=val;
45     if(k==n)
46     {
47         ans=min(ans,val);
48         return ;
49     }
50     for(register int i=1;i<=n;++i)
51         if(!d[i])
52             for(register int j=1;j<=n;++j)
53                 if(d[j]&&G[i][j]!=inf)
54                 {
55                     d[i]=d[j]+1;
56                     dfs(k+1,val+d[j]*G[i][j],(hsh+d[i]*hash[i])%Mod);
57                     d[i]=0;
58                 }
59 }
60 int main()
61 {
62     freopen("treasure.in","r",stdin);
63     freopen("treasure.out","w",stdout);
64     read(n);read(m);
65     init();
66     for(register int i=1;i<=m;++i)
67     {
68         int u,v,k;
69         read(u);read(v);read(k);
70         if(u==v)continue;
71         G[u][v]=min(G[u][v],k);
72         G[v][u]=min(G[v][u],k);
73     }
74     for(register int i=1;i<=n;++i)
75     {
76         d[i]=1;
77         dfs(1,0,hash[i]);
78         d[i]=0;
79     }
80     printf("%d\n",ans);
81     return 0;
82 }
NOIP2017 宝藏

 

posted @ 2017-12-20 21:16  HYJ_cnyali  阅读(321)  评论(0编辑  收藏  举报