1. 程式人生 > >【bzoj4720】【noip2016】【換座位】期望dp+Floyd

【bzoj4720】【noip2016】【換座位】期望dp+Floyd

對於剛上大學的牛牛來說,他面臨的第一個問題是如何根據實際情況申請合適的課程。在可以選擇的課程中,有2n節
課程安排在n個時間段上。在第i(1≤i≤n)個時間段上,兩節內容相同的課程同時在不同的地點進行,其中,牛牛預先
被安排在教室ci上課,而另一節課程在教室di進行。在不提交任何申請的情況下,學生們需要按時間段的順序依次完
成所有的n節安排好的課程。如果學生想更換第i節課程的教室,則需要提出申請。若申請通過,學生就可以在第i個
時間段去教室di上課,否則仍然在教室ci上課。由於更換教室的需求太多,申請不一定能獲得通過。通過計算,牛牛
發現申請更換第i節課程的教室時,申請被通過的概率是一個已知的實數ki,並且對於不同課程的申請,被通過的概率
是互相獨立的。學校規定,所有的申請只能在學期開始前一次性提交,並且每個人只能選擇至多m節課程進行申請。
這意味著牛牛必須一次性決定是否申請更換每節課的教室,而不能根據某些課程的申請結果來決定其他課程是否申
請;牛牛可以申請自己最希望更換教室的m門課程,也可以不用完這m個申請的機會,甚至可以一門課程都不申請。因
為不同的課程可能會被安排在不同的教室進行,所以牛牛需要利用課間時間從一間教室趕到另一間教室。牛牛所在
的大學有v個教室,有e條道路。每條道路連線兩間教室,並且是可以雙向通行的。由於道路的長度和擁堵程度不同,
通過不同的道路耗費的體力可能會有所不同。當第i(1≤i≤n-1)節課結束後,牛牛就會從這節課的教室出發,選擇一
條耗費體力最少的路徑前往下一節課的教室。現在牛牛想知道,申請哪幾門課程可以使他因在教室間移動耗費的體
力值的總和的期望值最小,請你幫他求出這個最小值。
Input
第一行四個整數n,m,v,e。n表示這個學期內的時間段的數量;m表示牛牛最多可以申請更換多少節課程的教室;
v表示牛牛學校裡教室的數量;e表示牛牛的學校裡道路的數量。
第二行n個正整數,第i(1≤i≤n)個正整數表示c,,即第i個時間段牛牛被安排上課的教室;保證1≤ci≤v。
第三行n個正整數,第i(1≤i≤n)個正整數表示di,即第i個時間段另一間上同樣課程的教室;保證1≤di≤v。
第四行n個實數,第i(1≤i≤n)個實數表示ki,即牛牛申請在第i個時間段更換教室獲得通過的概率。保證0≤ki≤1。
接下來e行,每行三個正整數aj,bj,wj,表示有一條雙向道路連線教室aj,bj,通過這條道路需要耗費的體力值是Wj;
保證1≤aj,bj≤v,1≤wj≤100。
保證1≤n≤2000,0≤m≤2000,1≤v≤300,0≤e≤90000。
保證通過學校裡的道路,從任何一間教室出發,都能到達其他所有的教室。
保證輸入的實數最多包含3位小數。
Output
輸出一行,包含一個實數,四舎五入精確到小數點後恰好2位,表示答案。你的
輸出必須和標準輸出完全一樣才算正確。
測試資料保證四舎五入後的答案和準確答案的差的絕對值不大於4*10^-3。(如果你不知道什麼是浮點誤差,這段話
可以理解為:對於大多數的演算法,你可以正常地使用浮點數型別而不用對它進行特殊的處理)
Sample Input
3 2 3 3
2 1 2
1 2 1
0.8 0.2 0.5
1 2 5
1 3 3
2 3 1
Sample Output
2.80

學了期望之後來看這道題,倒還算是有思路了。

首先,如果不換教室,就是最短路的問題。考慮到要查詢多個兩點最短距離和資料範圍,用Floyd是最好的。

那麼如果申請換教室,就有k的機率換成新路(距離可能會變長也可能變短),也有(1-k)的機率換不成教室。由期望的線性性就可以求出換教室的期望距離。

剩下的就是dp了。我們設dp[i][j][0/1]表示前i個時間段申請j次,第i個時間段是否申請換教室。轉移方程:
dp[i][j][0]=min(dp[i-1][j][1]+ee(i,0,i-1,1),dp[i-1][j][0]+map[c[i]][c[i-1]]);
dp[i][j][1]=min(dp[i-1][j-1][1]+ee(i,1,i-1,1),dp[i-1][j-1][0]+ee(i,1,i-1,0));
其中ee的函式是指期望路程:

double ee(int a,int sa,int b,int sb){
    if(sa==sb&&sa==0)
        return map[c[a]][c[b]];
    if(sa==1&&sb==0)
        return k[a]*map[d[a]][c[b]]+(1-k[a])*map[c[a]][c[b]];
    if(sa==0&&sb==1)
        return k[b]*map[c[a]][d[b]]+(1-k[b])*map[c[a]][c[b]];
    return k[b]*k[a]
*map[d[a]][d[b]]+(1-k[a])*k[b]*map[c[a]][d[b]]+(1-k[b])*k[a]*map[d[a]][c[b]]+(1-k[a])*(1-k[b])*map[c[a]][c[b]]; }

然後這道題有些基礎的細節忘完了,導致各種地方wa。下面羅列一下:
1、都申請的情況計算漏了一部分;
2、Floyd忘了給陣列賦初值無窮大;
3、dp的初值沒有考慮清楚
4、double型陣列不能用memset
wawawawawa。。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=2000+5;
const int V=300+5;
const int E=90000+5;
int n,m,v,e,c[N],d[N];
double map[V][V];
double dp[N][N][2],k[N];

double ee(int a,int sa,int b,int sb){
    if(sa==sb&&sa==0)
        return map[c[a]][c[b]];
    if(sa==1&&sb==0)
        return k[a]*map[d[a]][c[b]]+(1-k[a])*map[c[a]][c[b]];
    if(sa==0&&sb==1)
        return k[b]*map[c[a]][d[b]]+(1-k[b])*map[c[a]][c[b]];
    return k[b]*k[a]*map[d[a]][d[b]]+(1-k[a])*k[b]*map[c[a]][d[b]]+(1-k[b])*k[a]*map[d[a]][c[b]]+(1-k[a])*(1-k[b])*map[c[a]][c[b]];
}
int main(){
    scanf("%d%d%d%d",&n,&m,&v,&e);
    for(int i=1;i<=n;i++) scanf("%d",&c[i]);
    for(int i=1;i<=n;i++) scanf("%d",&d[i]);
    for(int i=1;i<=n;i++) scanf("%lf",&k[i]);
    for(int i=1;i<=v;i++)
        for(int j=1;j<=v;j++) if(i!=j) map[i][j]=0x7fffffff;
    for(int i=1;i<=e;i++){
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        map[a][b]=map[b][a]=min(map[a][b],(double)w);
    }
    for(int k=1;k<=v;k++)
        for(int i=1;i<=v;i++)
            for(int j=1;j<=v;j++){
                    map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
            }
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            dp[i][j][0]=dp[i][j][1]=0x7fffffff;
    dp[1][0][0]=dp[1][1][1]=0;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=min(i,m);j++){
            dp[i][j][0]=min(dp[i-1][j][1]+ee(i,0,i-1,1),dp[i-1][j][0]+map[c[i]][c[i-1]]);
            if(j!=0) dp[i][j][1]=min(dp[i-1][j-1][1]+ee(i,1,i-1,1),dp[i-1][j-1][0]+ee(i,1,i-1,0))
        }
    }
    double ans=0x7fffffff;
    for(int j=0;j<=m;j++){
        ans=min(ans,min(dp[n][j][1],dp[n][j][0]));
    }
    printf("%.2lf\n",ans);
    return 0;
}

相關推薦

bzoj4720noip2016座位期望dp+Floyd

對於剛上大學的牛牛來說,他面臨的第一個問題是如何根據實際情況申請合適的課程。在可以選擇的課程中,有2n節 課程安排在n個時間段上。在第i(1≤i≤n)個時間段上,兩節內容相同的課程同時在不同的地點進行,其中,牛牛預先 被安排在教室ci上

題解 bzoj1076: [SCOI2008]獎勵關 (裝壓+期望dp

狀態 span 方程 con can i+1 std tin log 題面戳我 Solution 並不會做,看了下題解大概了解了。期望這個東西好難搞啊qwq 我們定義\(dp[i][j]\)表示第\(i\)步,拿到寶物前的狀態為\(j\)。 正著來會有很多不合法的情況,剔

BZOJ2878: [Noi2012]迷失遊樂園-基環樹期望DP

傳送門:bzoj2878 題解 討論比較繁瑣: 先求出每個點向下走的期望 g i

NOIP2016」「P1850」 教室(期望dp

題目描述 對於剛上大學的牛牛來說,他面臨的第一個問題是如何根據實際情況申請合適的課程。 在可以選擇的課程中,有 2n2n 節課程安排在 nn 個時間段上。在第 ii(1 \leq i \leq n1≤i≤n)個時間段上,兩節內容相同的課程同時在不同的地點進

noip2016教室(期望dp)

整體思路: 這節課換了教室的期望路程 = min(上節課換了教室的期望路程 + 上節課教室到這節課教室的期望路程, 上節課沒換教室的期望路程+ 上節課教室到這節課教室的期望路程) 這節課沒換教室的期望路程 = min(上節課換了教室的期望路程  + 上節課教室到這節課教室的期望路程

bzoj4720[Noip2016]教室 期望dp+最短路

\n 課程 情況 memset 輸入 main 好的 can 結果 Description 對於剛上大學的牛牛來說,他面臨的第一個問題是如何根據實際情況申請合適的課程。在可以選擇的課程中,有2n節 課程安排在n個時間段上。在第i(1≤i≤n)個時間段上,兩節內容相同的課程同

bzoj 4720: [Noip2016]教室期望dp

zoj can 期望dp getchar [1] using main urn || 狀壓dp,設f[i][j][0/1]為前i個時間段換了j間教室的期望體力消耗,轉移很好想(但是寫起來好長= =) #include<iostream> #include<

雜記C#中的回車行符

語言 color 雜記 pan blog == 一行 div 屬性 在 C# 中,我們用字符串 "\r\n" 表示回車換行符。 如: string str = "第一行\r\n第二行"; 但是我們更推薦 Environment.NewLine(名稱空間為 System)

luogu P1850 教室 題解

題目連結:https://www.luogu.org/problemnew/show/P1850 難的不在狀態上,難在轉移方程。 (話說方程寫錯居然還有84分= =) #include <cstdio> #include <cstring> #include <iostre

Python程式設計Pycharm如何設定自動

Pycharm如何設定自動換行 在寫這篇IDE文章之前我在網上找了幾個文件做了參考。 我按照以上圖中找到了相關的配置選項並勾選如下: 設定完成後我測試是否可以換行,如下: 並沒有發現可以換行,於是我重新打開了pycharm再次嘗試,神奇的事情發生了,它還是沒有自動換行,找

NOIP 2016 教室

研讀資料,我們發現,28分是可以輕鬆拿到的: 對於的一個點,直接即可。 其餘的標紫色的資料點,跑一遍最短路,依次相加各個教室之間的最短路徑長度即可。 其實,↑ 也是建立在你知道期望是啥的基礎上的。 期望這個東西,本蒟蒻還是沒有理解它的線性.... 有

題解LuoGu2831/noip2016:憤怒的小鳥

原題傳送門 【題解】 我先想到了dfs,估計了一下時間複雜度,估不出來,覺得懸,就“瞟了一眼”題解,發現第一篇就是dfs,然後信心滿滿的碼好,莫名wa掉,找了很長時間錯也沒找出來。 然後我又想起一年前某位老師講狀壓dp的時候講過這道題,就改用了狀壓dp dp[i

模板樹鏈剖分+

樹鏈剖分 描述 給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有一個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別: 換根:將一個指定的節點設定為樹的新根。 修改路徑權值:給定兩個節點,將這兩個節點間路徑上的所有節點權值(含這兩個節

P2822組合數問題NOIP2016

題目描述 組合數 Cnm ​表示的是從 n 個物品中選出 m 個物品的方案數。舉個例子,從 (1,2,3) 三個物品中選擇兩個物品可以有 (1,2),(1,3),(2,3) 這三種選擇方法。根據組合數的定義,我們可以給出計算組合數 Cnm的一般公式: C nm

101635C Macarons 矩陣快速冪+狀壓dfs時間空間

【連結】 【題意】 求用1*1,1*2的方格填n*m的矩陣的方法數 【知識點】 狀壓dfs+矩陣快速冪 【分析】 每列狀態的狀態轉移壓縮,通過dfs狀壓求出每個狀態的鄰接矩陣,求出初始矩陣,再快速冪即可 【程式碼】 #include<stdio.h&

VBAセールの値は配列に変方法

code ext edi bound nbsp test class sub next 方法一 1 Sub test1() 2 //変數の定義 3 Dim a() As Integer, iRow As Long, i As Integer 4

語言-批處理批處理單獨輸入行符

echo.和echo/ 輸入單獨的換行,echo和點、斜槓之間沒有空格,單獨輸入echo顯示的是echo當前的狀態,如果之前使了echo off ,那麼提示就是“echo處於關閉狀態”;如果前面使用了“echo on”,那麼提示就是“echo處於開啟狀態”。 echo ec

javaweb表格的隔行

需求分析:商品分類資訊太多,每一行都是同一個顏色會讓人看得眼花繚亂,為了提高使用者體驗,我們需要對錶格進行隔行換色。 目標樣例如下:  技術分析: (1)確定事件:頁面載入完成事件onload (2)觸發函式:init() (3)函式操作:對錶格進行迴圈換色

LeetCode--資料庫座位

626.換座位(中等) 題目:小美是一所中學的資訊科技老師,她有一張seat 座位表,平時用來儲存學生名字和與他們相對應的座位id,其中縱列的 id 是連續遞增的,小美想改變相鄰倆學生的座位,寫一個 SQL query 來輸出小美想要的結果 注意:如果學生人數是奇數,則不

題解BZOJ4719:[Noip2016]天天愛跑步

首先膜拜一下大牛 感謝大佬的這篇題解 Description 小c同學認為跑步非常有趣,於是決定製作一款叫做《天天愛跑步》的遊戲。?天天愛跑步?是一個養成類遊戲,需要 玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 N個結點和N-1 條