日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

洛谷-省选斗兽场-动态规划1

發(fā)布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷-省选斗兽场-动态规划1 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

練習(xí)一下動態(tài)規(guī)劃水題系列,防止腦子生銹。

P1879 玉米田

題解

非常典型的狀態(tài)壓縮DPDP,先預(yù)處理出所有可行的狀態(tài)SS
然后逐行DPDP,定義狀態(tài)dp[i][S]dp[i][S]表示的含義是前ii行滿足條件,并且第ii行的狀態(tài)為SS,可行的方案數(shù)。

然后狀態(tài)轉(zhuǎn)移:dp[i+1][nS]=nSpS=0nSdp[i][pS]dp[i+1][nS]=∑nS與pS=0且nS可行dp[i][pS]

代碼

#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int maxs = 100000; const int mod = 1e8; int state[maxs]; int cnt = 0; int dp[13][maxs]; int bks[13]; int n,m; int main(){cin>>m>>n;for(int i = 1;i <= m;++i){for(int j = 0;j < n;++j){int t;cin>>t;if(t == 0) bks[i] |= (1<<j);}}for(int i = 0;i < (1<<n);++i){if(i&(i<<1)) continue;else state[cnt++] = i;}dp[0][0] = 1; int ans = 0;for(int i = 1;i <= m;++i){for(int j = 0;j < cnt;++j){int nS = state[j];if(nS & bks[i]) continue;for(int k = 0;k < cnt;++k){int pS = state[k];if(pS & nS) continue;dp[i][nS] += dp[i-1][pS];dp[i][nS] %= mod;} if(i == m) ans = (ans + dp[i][nS])%mod;}}cout<<ans<<endl; }

P1850 換教室

題解

有關(guān)概率期望的dp,但也不是很難,卻花了我很長時間,原因是初值條件沒搞清楚。

定義狀態(tài)

dp[i][j][0]dp[i][j][0]表示前ii個課程,換了jj個,且第ii個沒有換,期望值的最小值。

dp[i][j][1]dp[i][j][1]表示前ii個課程,換了jj個,且第ii個申請換了,期望值的最小值。

狀態(tài)轉(zhuǎn)移方程

dp[i][j][0]dp[i][j][0]的轉(zhuǎn)移方程:

由于第ii個課程沒有換教室,所以教室是a[i]a[i]的概率是1.01.0

  • 當(dāng)前i?1i?1沒有換的時候,第i?1i?1課程是教室a[i?1]a[i?1]的概率為1.01.0,轉(zhuǎn)移過來的數(shù)值是(dp[i?1][j][0]+mincost(a[i?1],a[i])?1.0?1.0(dp[i?1][j][0]+mincost(a[i?1],a[i])?1.0?1.0

  • 當(dāng)前i?1i?1換了的時候,如果換成功了,第i?1i?1課程是教室b[i?1]b[i?1]的概率為1.01.0,轉(zhuǎn)移過來的數(shù)值是(dp[i?1][j][1]+mincost(b[i?1],a[i])?p[i?1]?1.0(dp[i?1][j][1]+mincost(b[i?1],a[i])?p[i?1]?1.0

  • 當(dāng)前i?1i?1換了的時候,如果換失敗了,第i?1i?1課程是教室b[i?1]b[i?1]的概率為1.01.0,轉(zhuǎn)移過來的數(shù)值是(dp[i?1][j][1]+mincost(a[i?1],a[i])?(1?p[i?1])?1.0(dp[i?1][j][1]+mincost(a[i?1],a[i])?(1?p[i?1])?1.0

  • dp[i][j][1]dp[i][j][1]的轉(zhuǎn)移方程:

    由于第ii個課程申請換教室了,成功的概率是p[i]p[i],失敗的概率是1?p[i]1?p[i]

  • i?1i?1不申請換教室。
    轉(zhuǎn)移過來的數(shù)值為(dp[i?1][j?1][0]+G(a[i?1],b[i]))?p[i]+(dp[i?1][j?1][0]+G(a[i?1],a[i]))?(1?p[i])(dp[i?1][j?1][0]+G(a[i?1],b[i]))?p[i]+(dp[i?1][j?1][0]+G(a[i?1],a[i]))?(1?p[i])
  • 剩下的3種情況看我代碼里寫的吧,懶得去寫了。

    代碼

    #include <iostream> #include <cstdio> using namespace std; double dp[2][2007][2]; int G[307][307]; int n,m,v,e; int a[2007],b[2007]; double p[2007]; int main(){cin>>n>>m>>v>>e;for(int i = 0;i < n;++i){scanf(" %d",&a[i]);}for(int i = 0;i < n;++i){scanf(" %d",&b[i]);}for(int i = 0;i < n;++i){scanf(" %lf",&p[i]);}for(int i = 1;i <= v;++i){for(int j = 1;j <= v;++j){if(i == j) continue;G[i][j] = G[j][i] = 1e8;}}for(int i = 0;i < e;++i){int u,v,t;scanf(" %d %d %d",&u,&v,&t);G[v][u] = G[u][v] = min(t,G[v][u]);}for(int k = 1;k <= v;++k)for(int i = 1;i <= v;++i){for(int j = 1;j <= v;++j){G[i][j] = min(G[i][j],G[i][k] + G[k][j]);}}for(int i = 0;i < 2007;++i){dp[0][i][0] = dp[0][i][1] = dp[1][i][0] = dp[1][i][1] = 1e18;}dp[0][0][0] = 0;//dp[0][0][1] = 0;//dp[0][1][0] = 0;dp[0][1][1] = 0;for(int i = 1;i < n;++i){for(int j = 0;j <= min(m,i+1);++j){dp[i&1][j][0] = (dp[(i-1)&1][j][0]+G[a[i-1]][a[i]]);if(j == 0) continue;dp[i&1][j][0] = min(dp[i&1][j][0],(dp[(i-1)&1][j][1]+G[b[i-1]][a[i]])*p[i-1]+(dp[(i-1)&1][j][1]+G[a[i-1]][a[i]])*(1-p[i-1]));dp[i&1][j][1] = (dp[(i-1)&1][j-1][0]+G[a[i-1]][b[i]])*p[i]+(dp[(i-1)&1][j-1][0]+G[a[i-1]][a[i]])*(1-p[i]);if(j <= 1) continue;dp[i&1][j][1] = min(dp[i&1][j][1],dp[(i-1)&1][j-1][1]+G[b[i-1]][b[i]]*p[i-1]*p[i]+G[a[i-1]][b[i]]*(1-p[i-1])*p[i]+G[b[i-1]][a[i]]*(p[i-1])*(1-p[i])+G[a[i-1]][a[i]]*(1-p[i-1])*(1-p[i]));}}double ans = 1e18;for(int i = 0;i <= min(m,n);++i){ans = min(ans,dp[(n-1)&1][i][0]);ans = min(ans,dp[(n-1)&1][i][1]);}printf("%.2lf\n",ans); }

    P2831 憤怒的小鳥

    題解

    比較經(jīng)典的動態(tài)規(guī)劃問題。

    由于一條拋物線至少經(jīng)過1個點(diǎn)。我們構(gòu)造nn條拋物線,分別經(jīng)過這nn個點(diǎn),每條線都只能覆蓋11只豬。然后我們知道除了(0,0)(0,0)點(diǎn),剩下再有22個點(diǎn)就可以確定一條拋物線了。
    我們n2n2地枚舉兩兩點(diǎn)的組合,生成對應(yīng)的拋物線,這樣的話,最差情況下所需的不會超過n2n2條拋物線。
    我們把當(dāng)前構(gòu)造出來的每條拋物線,把這條拋物線能經(jīng)過的所有點(diǎn)壓縮成為一個狀態(tài)。
    問題就轉(zhuǎn)變成了狀態(tài)壓縮dp。

    定義狀態(tài)dp[S]dp[S]表示覆蓋SS狀態(tài)的點(diǎn),最小需要多少條拋物線。

    狀態(tài)轉(zhuǎn)移方程:
    dp[S|state[i]]=min(dp[S|state[i]],dp[S]+1)dp[S|state[i]]=min(dp[S|state[i]],dp[S]+1)
    其中state[i]state[i]表示第II<script type="math/tex" id="MathJax-Element-53">I</script>條拋物線所能經(jīng)歷的點(diǎn)集狀態(tài)。

    代碼

    #include <iostream> #include <cstring> #include <cstdio> #define pr(x) cout<<#x<<":"<<x<<endl using namespace std; int dp[1<<19]; int n,m; long double a[400],b[400]; int cover[400]; int cnt; long double x[40],y[20]; inline long double fabs(long double x) {return x > 0 ? x:-x;} long double eps = 0.000000001; int main(){int T;cin>>T;while(T--){cin>>n>>m;cnt = 0;memset(dp,0x3f,sizeof(dp));for(int i = 0;i < n;++i)cin>>x[i]>>y[i];for(int i = 0;i < n;++i){for(int j = i+1;j < n;++j){if(i == j) continue;if(fabs(x[i]-x[j]) < eps) {continue;}else{a[cnt] = (x[i]*y[j]-x[j]*y[i])/(x[j]*x[i]*(x[j]-x[i]));b[cnt] = (y[i] - a[cnt]*x[i]*x[i])/x[i];if(a[cnt] >= 0 || fabs(a[cnt]) < eps) continue;else cnt++;}}}dp[0] = 0;for(int i = 0;i < cnt;++i){int c = 0;for(int j = 0;j < n;++j){long double f = a[i]*x[j]*x[j] + b[i]*x[j];if(fabs(f - y[j]) < eps) c |= 1<<j;}cover[i] = c;}for(int i = 0;i < n;++i){cover[cnt++] = 1<<i;}for(int S = 0;S < (1<<n);++S){for(int j = 0;j < cnt;++j){dp[S|cover[j]] = min(dp[S|cover[j]],dp[S] + 1);}}cout<<dp[(1<<n)-1]<<endl;}return 0; }

    P1131 時態(tài)同步

    題解

    這是一道樹形dp。

    這道題的含義相當(dāng)于給邊添加最小的數(shù),使得從根節(jié)點(diǎn)道每個葉子節(jié)點(diǎn)路徑長度都相同。

    直接進(jìn)行dfs,回溯的時候保證子樹滿足題設(shè)條件(從根節(jié)點(diǎn)道每個葉子節(jié)點(diǎn)路徑長度都相同)。

    代碼

    // luogu-judger-enable-o2 #include <iostream> #include <cstdio> #include <vector> using namespace std; const int maxn = 500007; typedef pair<int,int> pii; vector<pii> G[maxn]; int n,root; long long ans = 0; int dfs(int u,int fa){vector<int> tv;int mx = 0;for(auto p : G[u]){int v = p.first;int c = p.second;if(v == fa) continue;int res = dfs(v,u)+c;tv.push_back(res);mx = max(mx,res);}for(auto v : tv){ans += mx - v;}return mx; } int main(){scanf("%d %d",&n,&root);for(int i = 0;i < n-1;++i){int u,v,c;scanf("%d%d%d",&u,&v,&c);G[u].push_back(make_pair(v,c));G[v].push_back(make_pair(u,c));}dfs(root,0);cout<<ans<<endl; }

    后記

    這幾道題目都是比較經(jīng)典的題目,就是太老了,下次應(yīng)該做一些新的題,這樣才能跟上時代潮流呀。

    總結(jié)

    以上是生活随笔為你收集整理的洛谷-省选斗兽场-动态规划1的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。