【比赛】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 }