NOIp2017D2T2(luogu3959) 宝藏 (状压dp)
时隔多年终于把这道题锅过了
数据范围显然用搜索剪枝状压dp。
可以记还有哪些点没到(或者已到了哪些点)、我们最深已到的是哪些点、这些点的深度是多少,然后一层一层地往下推。
但其实是没必要记最深的那一层的,只要强行装作每次更新都是用最深的深度更新就可以。这样的话,虽然会有很多情况偏大,但是能正确更新的情况其实是都已经包括了。
因为你如果想以当前状态去更新,但用的还不是最深一层的点的话,干脆就可以在之前你想用那个点处于最后一层的时候去更新。
代码写的很捉急..最后常数也很捉急...
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 #include<cmath> 7 #include<ctime> 8 #define LL long long int 9 #define inf 0x3f3f3f3f 10 using namespace std; 11 const int maxs=5000,maxn=15,maxm=1010; 12 13 LL rd(){ 14 LL x=0;char c=getchar();int neg=1; 15 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 16 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 17 return x*neg; 18 } 19 20 int eg[maxm*2][3],egh[maxn],ect; 21 int f[maxn][maxs],dis0[maxs][maxn],dis[maxs][maxs],bin[maxn]; 22 int N,M; 23 24 inline void adeg(int a,int b,int v){ 25 eg[ect][0]=b;eg[ect][1]=egh[a];eg[ect][2]=v;egh[a]=ect++; 26 for(int i=1;i<bin[N+1];i++) if((bin[a]&i) && !(bin[b]&i)) dis0[i][b]=min(dis0[i][b],v); 27 } 28 29 void dfs(int x,int y,int s,int e){ 30 if(x>N) dis[s][e]=y; 31 else{ 32 if(dis0[s][x]<=500000) dfs(x+1,y+dis0[s][x],s,e|bin[x]); 33 dfs(x+1,y,s,e); 34 } 35 } 36 37 int main(){ 38 int i,j,k; 39 N=rd(),M=rd(); 40 memset(egh,-1,sizeof(egh));memset(dis,127,sizeof(dis)); 41 memset(dis0,127,sizeof(dis0));memset(f,127,sizeof(f)); 42 for(i=1,j=1;i<=N+1;i++,j<<=1) bin[i]=j; 43 for(i=1;i<=M;i++){ 44 int a=rd(),b=rd(),c=rd(); 45 adeg(a,b,c);adeg(b,a,c); 46 } 47 for(i=1;i<bin[N+1];i++) dfs(1,0,i,0); 48 for(i=1;i<=N;i++) f[1][bin[i]]=0; 49 for(i=1;i<N;i++){ 50 for(j=1;j<bin[N+1];j++){ 51 if(f[i][j]>=9e7) continue; 52 for(k=1;k<bin[N+1];k++){ 53 if(dis[j][k]>500000) continue; 54 f[i+1][j|k]=min(f[i+1][j|k],f[i][j]+i*dis[j][k]); 55 } 56 } 57 }int ans=0x3f3f3f3f; 58 for(i=1;i<=N;i++) ans=min(f[i][(1<<N)-1],ans); 59 printf("%d\n",ans); 60 return 0; 61 }