[noip2017]寶藏
阿新 • • 發佈:2018-09-19
mes getchar() pri discus 出發點 tchar get not .com 一下。(來自洛谷討論版)
正確答案\(1043\)。我的代碼去掉剪枝是\(1043\),加上剪枝\(1046\)。
我原來的\(AC\)代碼
https://www.zybuluo.com/ysner/note/1286437
題面
戳我
解析
這確實是一道搜索可以過的題。。。
一般的暴力,就是枚舉出發點,記錄下當前已到過哪些點,以及每個點的深度(\(K\)值),然後對每個狀態枚舉走的下一條路的起點和終點。
當然,最優性剪枝誰都會。
這樣復雜度\(O(3^nn^3)\)。可以獲得\(70pts\)。
然而我們可以再加剪枝。
對於出發點相同的同一狀態,如果當前到達當前狀態的費用比以前的大,就可以停止搜索。
這樣就可以\(AC\)。。。
顯然這個剪枝是有問題的,因為後面的結果還受當前狀態中每個點的深度的影響。也可能當前不優,最後能最優呢。
給一組數據\(Hack\)
正確答案\(1043\)。我的代碼去掉剪枝是\(1043\),加上剪枝\(1046\)。
我原來的\(AC\)代碼
il void upd(re int &x,re int y){x=x<y?x:y;} il void dfs(re int tag,re int sum) { if(sum>=ans) return; if(tag==(1<<n)-1) {upd(ans,sum);return;} fp(s,1,n) if(d[s]) fp(t,1,n) if(!d[t]&&mp[s][t]!=inf) { re int nxt=tag|(1<<t-1),res=sum+d[s]*mp[s][t]; if(f[nxt]>res)//剪枝 { d[t]=d[s]+1; f[nxt]=res; dfs(nxt,res); d[t]=0; } } } int main() { n=gi();m=gi(); fp(i,0,19) fp(j,0,19) mp[i][j]=inf; fp(i,1,m) { re int u=gi(),v=gi(),w=gi(); mp[u][v]=mp[v][u]=min(mp[u][v],w); } fp(i,1,n) { memset(d,0,sizeof(d));memset(f,63,sizeof(f)); d[i]=1;f[1<<i-1]=0; dfs(1<<i-1,0); } printf("%d\n",ans); return 0; }
下面來談一談有理有據的算法。
用二進制表示結點集合,設\(f[i][j]\)表示點\(i\)在當時可走點的集合為\(j\)的情況下,下一步走的距離最小是多少。
此時點深度也是確定的,所以也能保證答案最小。
再設\(dp[i][j]\)表示當前加入深度為\(i\)的點,此時已加入點集合為\(j\)的最小代價。
然後按照深度依次更新\(dp\)值,就沒有後效性的問題了。
具體來說,是先枚舉深度,再枚舉加完點後的集合,再枚舉其子集(即加點前的集合)。最後在加點前的集合中枚舉出發點,以統計\(f\)的和。
復雜度\(O(3^nn^2)\)。
所以這題應該放\(T3\)的。。。
#include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<cstdlib> #include<algorithm> #define ll long long #define re register #define il inline #define max(a,b) (((a)>(b))?(a):(b)) #define min(a,b) (((a)<(b))?(a):(b)) #define fp(i,a,b) for(re int i=a;i<=b;i++) #define fq(i,a,b) for(re int i=a;i>=b;i--) using namespace std; const int N=13,inf=5e6; int n,m,all,dis[N][N],f[N][1<<N],dp[N][1<<N],s; il ll gi() { re ll x=0,t=1; re char ch=getchar(); while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar(); if(ch==‘-‘) t=-1,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-48,ch=getchar(); return x*t; } int main() { n=gi();m=gi();all=(1<<n)-1; fp(i,0,12) fp(j,0,12) dis[i][j]=inf; fp(i,0,12) fp(j,0,(1<<N)-1) f[i][j]=dp[i][j]=inf; fp(i,1,m) { re int u=gi(),v=gi(),w=gi(); dis[u][v]=dis[v][u]=min(dis[u][v],w); } fp(i,1,n) fp(j,0,all) fp(k,1,n) if((j>>k-1)&1) f[i][j]=min(f[i][j],dis[i][k]); fp(i,1,n) dp[1][1<<i-1]=0; fp(i,2,n) fp(j,0,all) for(re int k=j;k;k=(k-1)&j) { s=0; fp(l,1,n) if(((j^k)>>l-1)&1) s+=f[l][k]; dp[i][j]=min(dp[i][j],dp[i-1][k]+s*(i-1)); } printf("%d\n",dp[n][all]); return 0; }
[noip2017]寶藏