Game Rooms HDU - 5550

Your company has just constructed a new skyscraper, but you just noticed a terrible problem: there is only space to put one game room on each floor! The game rooms have not been furnished yet, so you can still decide which ones should be for table tennis and which ones should be for pool. There must be at least one game room of each type in the building.

Luckily, you know who will work where in this building (everyone has picked out offices). You know that there will be Ti table tennis players and Pi
pool players on each floor. Our goal is to minimize the sum of distances for each employee to their nearest game room. The distance is the difference in floor numbers: 0 if an employee is on the same floor as a game room of their desired type, 1 if the nearest game room of the desired type is exactly one floor above or below the employee, and so on.
Input
The first line of the input gives the number of test cases, T(1≤T≤100). T test cases follow. Each test case begins with one line with an integer N(2≤N≤4000), the number of floors in the building. N lines follow, each consists of 2 integers, Ti and Pi(1≤Ti,Pi≤109), the number of table tennis and pool players on the ith
floor. The lines are given in increasing order of floor number, starting with floor 1 and going upward.
Output
For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y
is the minimal sum of distances.
Sample Input

1
2
10 5
4 3

Sample Output

Case #1: 9

题意:有一栋楼,每一层由喜欢乒乓球的和喜欢游泳的人组成,每一层可以选择建立一个乒乓球或者游泳池(只能选择一个),那么每个人距离他喜欢的活动的距离就是他的贡献,问所有人的贡献和最小是多少。
做法:dp,设两个dp,dp[0][i]代表处理到前i层,第i层选择乒乓球,第i-1层必定是游泳池的最小贡献,dp[1][i]代表处理到前i层,第i层选择乒乓球,第i+1层必定选择游泳池的最小贡献,
那么对于dp[0][i],枚举他下面的游泳池的层数,dp[0][i] = min(dp[1][j]+(j+1到i-1之间的喜欢乒乓球的人的贡献))(j

#include<bits/stdc++.h>
using namespace std;
const int N = 4100;
long long t[N],p[N];
long long ft[N],bt[N];
long long fp[N],bp[N];
long long dp[2][N];
int n;
long long sum(int op,int ff,int l,int r){
    if(l > r) return 0;
    long long *fx,*bx,*x;
    if(op == 0) {
        fx = ft,bx = bt,x =t;
    }
    else fx = fp,bx = bp,x = p;
    if(ff == 0){
        return fx[r]-fx[l-1]-(l-1)*(x[r]-x[l-1]);
    }
    else return bx[l]-bx[r+1]-(n-r)*(x[r]-x[l-1]);
}

int main(){
    int T;
    cin >> T;
    for(int kase = 1;kase <= T;kase ++){
        scanf("%d",&n);
        bp[n+1] = bt[n+1] = 0;
        for(int i = 1;i <= n;i ++) scanf("%lld %lld",&t[i],&p[i]);
        for(int i = 1;i <= n;i ++){
            ft[i] = i*t[i];
            ft[i] += ft[i-1];
            fp[i] = i*p[i];
            fp[i] += fp[i-1];
        }
        for(int i = n;i >= 1;i --){
            bt[i] = (n+1-i)*t[i];
            bt[i] += bt[i+1];
            bp[i] = (n+1-i)*p[i];
            bp[i] += bp[i+1];
        }
        for(int i = 1;i <= n;i ++) t[i] += t[i-1],p[i] += p[i-1];
        for(int i = 1;i <= n;i ++) dp[1][i] = dp[0][i] = 1e18;
        dp[1][1] = p[1];
        for(int i = 2;i <= n;i ++){
            dp[0][i] = p[i]-p[i-1]+sum(0,1,1,i-1);
            dp[1][i] = min(dp[0][i],sum(1,1,1,i));
            for(int j = 1;j < i-1;j ++){
                dp[0][i] = min(dp[0][i],dp[1][j]+p[i]-p[i-1]+sum(0,0,j+1,(i+j)/2)+sum(0,1,(i+j)/2+1,i-1));
            }
            for(int j = 2;j <= i-1;j ++){
                dp[1][i] = min(dp[1][i],dp[0][j]-p[j]+p[j-1]+sum(1,0,j,(i+j)/2)+sum(1,1,(i+j)/2+1,i));
            }
            for(int j = 1;j < i-1;j ++){
                dp[1][i] = min(dp[1][i],dp[1][j]+p[i]-p[i-1]+sum(0,0,j+1,(i+j)/2)+sum(0,1,(i+j)/2+1,i-1));
            }
            //cout << i <<' '<<dp[0][i] << ' '<< dp[1][i] << endl;
        }
        long long ans = 1e18;
        for(int i = n-1;i >= 1;i --){
            ans = min(ans,sum(0,0,i+1,n)+dp[1][i]);
        }
        for(int i = n;i > 1;i --){
            ans = min(ans,sum(1,0,i,n)+dp[0][i]-p[i]+p[i-1]);
        }
        printf("Case #%d: %lld\n",kase,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zstu_zy/article/details/81060360
今日推荐