noip2017d2t2
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                noip2017d2t2
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                看數據范圍想到狀壓,我們知道最后是選出一顆生成樹,但邊權的計算有一些有趣;
我們先選一個點做根;然后就發現邊的權和深度有關;那我們按深度dp;即按層dp;
dp[i][s]表示前i層選的點集為s,轉移時我們枚舉s的補集的子集ss;對于ss中的每個點,
我們連上他到s中點的最小邊;但這樣連的邊沒辦法保證深度為i+1,但我們就強制把他設成i+1;
這樣感覺很錯,但其實是對的,因為這樣只會使答案變大,而且還可以保證真正的答案被枚舉到;
相當于是一種對限制的擴大。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdio> using namespace std; typedef long long ll; const ll inf=1e16; ll map[20][20],dis[15][(1<<12)+10]; ll dp[15][(1<<12)+10],z; int n,m,x,y; int main(){cin>>n>>m;if(!m){puts("0");return 0;}for(int i=0;i<=12;++i)for(int j=0;j<=12;++j)map[i][j]=inf;for(int i=0;i<=12;++i)for(int j=0;j<=(1<<12);++j)dis[i][j]=inf;for(int i=0;i<=12;++i)for(int j=0;j<=(1<<12);++j)dp[i][j]=inf;for(int i=1;i<=m;++i){scanf("%d%d%d",&x,&y,&z);map[x][y]=map[y][x]=min(map[x][y],z);}int sta=(1<<n)-1;for(int s=1;s<=sta;++s){for(int i=1;i<=n;++i){if((1<<(i-1))&s)continue;for(int j=1;j<=n;++j){if((1<<(j-1))&s)dis[i][s]=min(dis[i][s],map[i][j]);}}}for(int i=1;i<=n;++i)dp[1][1<<(i-1)]=0;for(int s=1;s<=sta;++s){int st=sta-s;for(int ss=st;ss;ss=(ss-1)&st){ll res=0;for(int i=1;i<=n;++i){if((1<<(i-1))&ss)res+=dis[i][s];}for(ll i=1;i<n;++i){dp[i+1][ss|s]=min(dp[i+1][ss|s],dp[i][s]+res*i);}}}ll ans=inf;for(int i=2;i<=n;++i)ans=min(ans,dp[i][sta]);cout<<ans;return 0; }?
轉載于:https://www.cnblogs.com/dibaotianxing/p/7922911.html
總結
以上是生活随笔為你收集整理的noip2017d2t2的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 构建创业公司突击小团队
- 下一篇: 穿越火线
