1. 程式人生 > >noip模擬【service】

noip模擬【service】

最小 int main 最後一行 floyd 請求 out print open

service

【問題描述】

一家公司為它在各地的用戶提供服務,公司有三名負責這項工作的員工,分別編號為1,2,3,服務的地點有n個,分別編號為1,2,3,...n,把從編號為p的服務地點直接到達編號為q的服務地點所需的移動費用記為C(p,q),顯然C(p,p)=0(停留在原地不需要費用),但不保證對任意p,q均有C(p,q)=C(q,p)。

初始時員工1在地點1,員工2在地點2,員工3在地點3,現在公司依次收到了L個服務請求,每個請求需要一名員工趕到其指定的地點進行服務,員工可以選擇直達,也可以選擇經過若幹個服務地點中轉,特別地,如果指派的員工已在當前請求所在地,則該請求不需要任何移動費用即可被處理。

出於公平起見,所有請求必須按順序處理,這意味著即使一名員工在趕往當前請求的途中經過之後的請求所在的地點,他也不可以先處理之後的請求,但是公司不限制每位員工趕往請求地點的路線,也允許一個服務地點有多名員工。

你的任務就是對於這L個請求,找到一個服務方案(即對每個請求分配合適的員工去服務以及規劃移動路線),使得三名員工提供服務的總移動費用最小。

【輸入格式】

每個測試點第一行為一個正整數T,表示該測試點內的數據組數,你需要對該測試點內的T組數據都分別給出正確的答案才能獲得該測試點的分數。

接下來T組數據,每組數據第一行兩個正整數n和L,含義如題目所述,接下來n行,每行n個非負整數,其中第p行第q個數表示C(p,q),最後一行包含一行L個正整數,依次描述每個請求指定的地點。

【輸出格式】

對每組數據輸出一行一個非負整數,表示最小的總移動費用。

【輸入輸出樣例】

service.in

service.out

2

3 6

0 1 2

3 0 4

5 6 0

1 2 3 1 2 3

5 9

0 1 1 1 1

1 0 2 3 2

1 1 0 4 1

2 1 5 0 1

4 2 3 4 0

4 2 4 1 5 4 3 2 1

0

5

【樣例解釋】

第一組測試數據中,所有可能的地點都有員工,因此不需要進行任何移動。

第二組測試數據中,三位員工初始在1 2 3三個地方,下面給出其中一種達到最小總移動費用的方案:

請求地點

指派員工

移動路線

員工所在地

當前總代價

(初始狀態)

1 2 3

0

4

1

1->4

4 2 3

0+1=1

2

2

2

4 2 3

1+0=0

4

1

4

4 2 3

1+0=1

1

2

2->1

4 1 3

1+1=2

5

2

1->5

4 5 3

2+1=3

4

1

4

4 5 3

3+0=3

3

3

3

4 5 3

3+0=3

2

1

4->2

2 5 3

3+1=4

1

3

3->1

2 5 1

4+1=5

【數據規模與約定】

每個測試點5分,各個測試點數據範圍如下:

測試點編號

n

L

1-3

n<=10

L<=10

4-6

n<=40

L<=10

7-10

n<=40

L<=100

11-14

n<=100

L<=100

15-17

n<=100

L<=500

18-20

n<=200

L<=500

對於所有的測試點,均有數據組數T<=5,地點數n>=3,給定的C矩陣主對角線上的數全部為0,且輸入數據中所有的數均為不超過2000的非負整數。

同TYVJ1061【mobile service】

乍一眼看過去,不就是個dp嗎,啪啪啪四維dp碼完,看復雜度感覺有點不對啊,數組好像有點大啊,面臨TLE和MLE的雙風險。

很明顯,這個四維dp的解法十分不優秀。

f[i][x][y][z]表示到了第i個階段,x,y,z分別表示三個人的位置。

然後轉移考慮最小代價即可。

思考優化:去除冗雜信息。

對於這三個人的位置,只需要得知兩個,要麽更新的是這兩個其中之一,兩個人位置都不更新就是剩下的一個位置進行了更新。

只需三維,代碼如下:

ps:為什麽要用floyd求任意兩點之間的最短距離。(本題與tyvj1061的區別)

是否限制每個地點的員工數量。這點沒看出來也是這題的丟分原因,我沒有floyd。

給出service的代碼

#include<bits/stdc++.h>
using namespace std;
const int maxn = 200+5;
const int maxL = 500+5;
const int inf = 1e9;
int T,n,L,ans;
int c[maxn][maxn],f[maxL][maxn][maxn],p[maxL];
inline int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;    
}
void work(){
    p[0] = 3;
    f[0][1][2] = 0;//記錄1,2的狀態
    for(int i = 1;i <= L; ++i){
        for(int j = 1;j <= n; ++j){
            for(int k = 1;k <= n; ++k){
                f[i][j][k] = min(f[i][j][k],f[i-1][j][k]+c[p[i-1]][p[i]]);
                f[i][p[i-1]][k] = min(f[i][p[i-1]][k],f[i-1][j][k]+c[j][p[i]]);
                f[i][j][p[i-1]] = min(f[i][j][p[i-1]],f[i-1][j][k]+c[k][p[i]]);
            }
        }
    } 
    for(int i = 1;i <= n; ++i){
        for(int j = 1;j <= n; ++j){
            ans = min(ans,f[L][i][j]);
        } 
    }
    printf("%d\n",ans);
}
int main(){
    freopen("service.in","r",stdin);
    freopen("service.out","w",stdout);
    T = read();
    while(T--){
        ans = inf;
        memset(f,0x3f,sizeof(f));
        n =read(); L = read();
        for(int i = 1;i <= n; ++i){
            for(int j = 1;j <= n; ++j){
                c[i][j] = read();
            }
        }
        for(int i =1;i <= L; ++i) p[i] = read();
        for(int k = 1;k <= n; ++k){
            for(int i = 1;i <= n; ++i){
                for(int j = 1;j <= n; ++j){
                    c[i][j] = min(c[i][j],c[i][k]+c[k][j]);
                }
            }
        }
        work();
    }
    return 0;
} 

noip模擬【service】