1. 程式人生 > 實用技巧 >CF82D Two out of Three

CF82D Two out of Three

題目描述

Vasya has recently developed a new algorithm to optimize the reception of customer flow and he considered the following problem.

Let the queue to the cashier contain n n n people, at that each of them is characterized by a positive integer ai a_{i} ai — that is the time needed to work with this customer. What is special about this very cashier is that it can serve two customers simultaneously. However, if two customers need ai a_{i} ai and aj a_{j} aj of time to be served, the time needed to work with both of them customers is equal to max(ai,aj) max(a_{i},a_{j}) max(ai,aj) . Please note that working with customers is an uninterruptable process, and therefore, if two people simultaneously come to the cashier, it means that they begin to be served simultaneously, and will both finish simultaneously (it is possible that one of them will have to wait).

Vasya used in his algorithm an ingenious heuristic — as long as the queue has more than one person waiting, then some two people of the first three standing in front of the queue are sent simultaneously. If the queue has only one customer number i i i , then he goes to the cashier, and is served within ai a_{i} ai of time. Note that the total number of phases of serving a customer will always be equal to ⌈n/2⌉ ⌈n/2⌉ n/2⌉ .

Vasya thinks that this method will help to cope with the queues we all hate. That's why he asked you to work out a program that will determine the minimum time during which the whole queue will be served using this algorithm.

輸入格式

The first line of the input file contains a single number n n n ( 1<=n<=1000 1<=n<=1000 1<=n<=1000 ), which is the number of people in the sequence. The second line contains space-separated integers a1,a2,...,an a_{1},a_{2},...,a_{n} a1,a2,...,an ( 1<=ai<=106 1<=a_{i}<=10^{6} 1<=ai<=106 ). The people are numbered starting from the cashier to the end of the queue.

輸出格式

Print on the first line a single number — the minimum time needed to process all n n n people. Then on ⌈n/2⌉ ⌈n/2⌉ n/2⌉ lines print the order in which customers will be served. Each line (probably, except for the last one) must contain two numbers separated by a space — the numbers of customers who will be served at the current stage of processing. If n n n is odd, then the last line must contain a single number — the number of the last served customer in the queue. The customers are numbered starting from 1 1 1 .

題意翻譯

一隊顧客排在一位收銀員前面。他採取這樣一個策略:每次,假如隊伍有至少兩人,就會從前面的前三人(如果有)中選取兩位一起收銀,所花費的時間為這兩人單獨收銀所需時間的最大值。如果只有兩人,那麼一起收銀;如果只有一人,那麼單獨收銀。請問所需的總時間最少是多少?

輸入輸出樣例

輸入 #1
4
1 2 3 4
輸出 #1
6
1 2
3 4
輸入 #2
5
2 4 3 1 4
輸出 #2
8
1 3
2 5
4
考慮dp

發現不好搞,在不同的情況下選擇不同的數會造成不同的影響
考慮狀態的設計,發現對於不同的情況,不一樣的其實是當前3個數和選到了第幾個數
可以在狀態中記錄一下目前3個數,發現只用記錄前面留下的即可

設f[i][j]表示選到了第i個數,前面留下的是第j個數時的最優解
然後就沒什麼了
轉移應該是很顯而易見的

code

//¼ÓÓÍ
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int f[1001][1001],n,a[1001],out[1001][1001][3];
inline ll read()
{
    char c=getchar();ll a=0,b=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;
    return a*b;
}
inline void az(int i,int j,int x,int y,int z){out[i][j][0]=x;out[i][j][1]=y;out[i][j][2]=z;}
void prout(int x,int y)
{
    if(y==0)return;
    prout(x-1,out[x][y][2]);
    if(out[x][y][0]<=n)
    {
        cout<<out[x][y][0]<<' ';
    }
    if(out[x][y][1]<=n)
    {
        cout<<out[x][y][1]<<' ';
    }
    cout<<endl;
}
int main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
    }
    memset(f,0x3f,sizeof(f));
    f[1][1]=max(a[2],a[3]);f[1][2]=max(a[1],a[3]);f[1][3]=max(a[1],a[2]);
    az(1,1,2,3,0);
    az(1,2,1,3,0);
    az(1,3,1,2,0);
    int m=(n&1)?n/2+1:n/2;
    for(int i=2;i<=m;i++)
    {
        int x=i<<1,y=i<<1|1;
        for(int j=1;j<x;j++)
        {
            if(f[i][x]>f[i-1][j]+max(a[j],a[y]))
            {
                f[i][x]=f[i-1][j]+max(a[j],a[y]);
                az(i,x,j,y,j);
            }
            if(f[i][y]>f[i-1][j]+max(a[j],a[x]))
            {
                f[i][y]=f[i-1][j]+max(a[j],a[x]);
                az(i,y,j,x,j);
            }
            if(f[i][j]>f[i-1][j]+max(a[x],a[y]))
            {
                f[i][j]=f[i-1][j]+max(a[x],a[y]);
                az(i,j,x,y,j);
            }
        }
    }
    cout<<f[m][n+1]<<endl;
    prout(m,n+1);
    return 0;
}