1. 程式人生 > 實用技巧 >WOJ1022 Competition of Programming 貪心 WOJ1023 Division dp

WOJ1022 Competition of Programming 貪心 WOJ1023 Division dp


title: WOJ1022 Competition of Programming 貪心
date: 2020-03-19 13:43:00
categories: acm
tags: [acm,woj,貪心]

貪心。

1 描述

There are many good reasons for participating in programming contests. You can have fun while you improve both your programming
skills and job prospects in the bargain. From somewhere in this vein arises TopCoder, a company which uses programming contests as a
tool to identify promising potential employees and provides this information to its clients.

The format of TopCoder contests is evolving quickly as they hunt for the most appropriate business model. Preliminary rounds are
held over the web, with the final rounds of big tournaments held on site. Each of these rounds shares the same basic format. The coders
are divided into ?rooms? where they compete against the other coders. Each round starts with a coding phase of 75?80 minutes where the
contestants do their main programming. The score for each problem is a decreasing function of the time from when it was first opened to
when it was submitted. There is then a 15-minute challenge phase where coders get to view the submissions from other contestants in their
room and try to find bugs. Coders earn additional points by submitting a test case that breaks another competitor?s program. There is no
partial credit for incorrect solutions. Is it very interesting and exciting for participating in TopCoder and you just want to participate
it right now?
Now, WOJ (Wuhan University Online Judge) development group will introduce the TopCoder contest format into WOJ. Of course, there
will be something different from TopCoder and we will set some new regulations into WOJ?s TopCoder. Here is one of these regulations: in
the coding phase, we will set the finish time limit T and penalty C for each problem. If you don?t solve the i-th problem in the finish time
limit Ti, your penalty will be added by Ci. Note that the penalty here is completely different from the penalty in ACM. The penalty in WOJ?s
TopCoder is a value set by us and is be independent of the problem solving time.
Assume that you are a genius in programming and it takes only one time unit for you to solve one problem whatever the problem is.
Now, there are N problems in WOJ?s TopCoder contest and the finish time limit and penalty of each problem is given, please write a program
to calculate minimum penalty you will get.

輸入格式
Standard input will contain multiple test cases. The first line of the input is a single integer T (1 <= T <= 50) which is the number of test cases.

The first line of each test case contains only one integer N (1 <= N <= 3000) which specify the total problem numbers. The next N lines each contains the description for one problem, the first integer T (1 <= T <= 3000) specifying the finish time limit and the second integer C (1 <= C <= 50000) specifying the penalty.

輸出格式
Results should be directed to standard output. Start each case with "Case #:" on a single line, where # is the case number starting from 1. Two consecutive cases should be separated by a single blank line. No blank line should be produced after the last test case.

For each test case, print one integer, the minimum penalty described as above.

樣例輸入
2
3
1 5
3 2
3 4
3
1 5
2 2
2 4
樣例輸出
Case 1:
0

Case 2:
2

2 分析

// 貪心。和上學期演算法期末考試一道題很像。
//這裡讀題的時候想了一會兒才發現每道題沒有說完成耗時,那麼就是說一個時間點就完成了
//期末那道題還考慮到佔用時間,這裡佔用時間就是1
//總之就算每道題儘量拖到允許時間的最後再執行,這樣可以給其他題留下更多時間。(像一條線段上視窗越靠後越好)
//因為這裡還有罰時,貪心策略是罰時越高越先優執行
//所以先根據罰時排序,然後從高優先順序的problem開始,儘量靠後的找到時間點;

3 code

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

struct problem{
    int time,penalty;
    bool operator <(const problem &tmp)const{
        return penalty>tmp.penalty;
    }
};

/*
 if(a.grade != b.grade) 
        return a.grade < b.grade; 
    else if(t != 0)
        return t < 0; 
    else
        return a.age < b.age;
*/

problem probs[3005];
int T=0,casee=0,n;

bool vis[3005];  

// 50000*3000=150000000=1.5e8.  [-2^31,2^31),即-2147483648~2147483647約等於2e9,沒超
int solve()  
{  
    int res = 0;
	memset(vis, 0, sizeof(vis));  
    for(int i = 0; i < n; i++){  
        bool ok = false;
		for(int j= probs[i].time; j >= 1; j--) { //time 從 1開始所以>=1
            if(!vis[j]) {       //還沒被佔用,就在這裡完成  
                vis[j] = true;  
                ok = true;  
                break;  
            }  
        } 
        if(!ok) res += probs[i].penalty;  
    } 
    return res;  
}  

int main(){

    cin>>T;
    while(T--){
        cin>>n;
        if(casee!=0)
            cout<<endl;
        casee++;
        printf("Case %d:\n",casee);
        for(int i=0;i<n;i++)
            cin>>probs[i].time>>probs[i].penalty;
        sort(probs,probs+n);
        printf("%d\n",solve());
    }
    system("pause");
    return 0;
}

title: WOJ1023 Division dp
date: 2020-03-19 13:43:00
categories: acm
tags: [acm,woj,dp]

動態規劃

1 描述

輸入格式
Standard input will contain multiple test cases. The first line of the input is a single integer T (1 <= T <= 50) which is the number of test cases.

Each test case begins with a line containing two integers n (1 <= n <= 100) and p (1 <= p <= n), where n represents the size of the set and p represents the least number of elements each cluster must contain. The second line contains positive integers (you are ensured that the value of each integer is less than 2^16), which are separated by a white space denoting the elements of the set.

輸出格式
Results should be directed to standard output. Start each case with "Case #:" on a single line, where # is the case number starting from 1. Two consecutive cases should be separated by a single blank line. No blank line should be produced after the last test case.

For each test case, you should output one line containing a floating number, which is the minimum sum of the squared deviation of the numbers from their cluster mean. The answer should be accurate to two fractional digits.

樣例輸入
2
2 1
1 2
2 2
1 2
樣例輸出
Case 1:
0.00

Case 2:
0.50

2 分析

給出一個集合大小為n,要把內部的元素分成clusters(簇),每個簇至少大小為p
每個簇S均值S'為 ai求和/|S| |S|為簇S的size
每個簇的值為內部元素 (ai-S'^2)之和
求各個簇如何分,值之和最小
Each cluster contains consecutive number cluster內的數字是連續的

前面的分簇結果可以被後面利用
dp 狀態轉移方程: f[i]=min(f[i],f[j]+valuecluser[j+1][i])(i-j>=p) //j+1...(注意分界點)
dp[0]=0.i in range p-1-N (編號為1-n)
//dp注意初始狀態結束狀態預處理。f[0]=0,f[i]初始為maxd
預處理:計算valuecluster[i][j]

3 code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath> //pow
#include<algorithm> //min
using namespace std;

int T=0,casee=0,n,p,i,j,k;
const double maxd=1e15;    //2^16*2^16*100 2E11
double summ[105][105]; //存連續數字和
int nums[105];
double clustervalue[105][105];
double f[105]; //dp

double dp(){
    for(i=p;i<=n;i++)
        for(j=i-p;j>=0;j--){ //一開始寫成i-p+1了...
            f[i]=min(f[i],f[j]+clustervalue[j+1-1][i-1]); //f[i]中元素編號+1,計算的時候注意減1
        }
    return f[n];
}

int main(){

    cin>>T;
    while(T--){
        cin>>n>>p;
        for(i=0;i<n;i++)
            cin>>nums[i];
        for(i=0;i<n;i++)
            for(j=i;j<n;j++)
                {
                    if(i==j)
                    summ[i][j]=nums[i];
                    else
                    summ[i][j]=summ[i][j-1]+nums[j];
                }
        for(i=0;i<n;i++)
            for(j=i;j<n;j++)
                {
                    clustervalue[i][j]=0;
                }
        for(i=0;i<n;i++)
            for(j=i+p-1;j<n;j++)
                {
                    double avg=summ[i][j]*1.0/(j-i+1);
                    for(k=i;k<=j;k++)
                    clustervalue[i][j]+=pow(nums[k]-avg*1.0,2);
                }
        for(i=1;i<=n;i++)
            f[i]=maxd;
        f[0]=0; //初始狀態
        if(casee!=0)
            cout<<endl;
        casee++;
        printf("Case %d:\n",casee);
        printf("%.2lf\n",dp());
        
    }
    system("pause");
    return 0;
}