TopCoder SRM 667 Div.2题解

概览:
T1 枚举 T2 状压DP T3 DP


TopCoder SRM 667 Div.2 T1

原题

Problem Statement

You are given two distinct points A and B in the two-dimensional plane. Your task is to find any point C with the following properties:
C is different from A and B.
Each coordinate of C is an integer between -100 and 100, inclusive.
The distance between A and C is strictly greater than the distance between B and C.
You are given four ints: x1, y1, x2, and y2. Point A has coordinates (x1,y1) and point B has coordinates (x2,y2). Find the coordinates (x3,y3) of one possible point C with the above properties. Return these coordinates as a vector with two elements: element 0 is x3 and element 1 is y3. In other words, return the vector {x3,y3}.
For the constraints given below it is guaranteed that a valid point C always exists. If there are multiple solutions, return any of them.

Definition

Class:
PointDistance
Method:
findPoint
Parameters:
int, int, int, int
Returns:
vector
Method signature:
vector findPoint(int x1, int y1, int x2, int y2)
(be sure your method is public)

Limits

Time limit (s):
2.000
Memory limit (MB):
256
Stack limit (MB):
256

Notes

In this problem we consider the standard Euclidean distance. Formally, the distance between points (xi,yi) and (xj,yj) is defined as sqrt( (xi-xj)^2 + (yi-yj)^2 ).

Constraints

x1,y1,x2,y2 will be between -50 and 50, inclusive.
(x1,y1) will be different from (x2,y2).

Examples

0)

-1
0
1
0
Returns: {8, 48 }
In this example, point A is at (-1,0) and point B is at (1,0). Almost any point with a positive x-coordinate will be a valid answer. For example, your program can also return {100,100}, {2,0}, or {9,-100}. Note that you cannot return {1,0} because point C must not be the same as point B.
1)

1
1
-1
-1
Returns: {25, -63 }
(x1,y1) is (1,1) and (x2,y2) is (-1,-1).
2)

0
1
2
3
Returns: {41, 65 }

3)

5
-4
-2
5
Returns: {68, 70 }

4)

-50
-50
50
-50
Returns: {67, 4 }

5)

-50
50
-49
49
Returns: {73, -25 }

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.

解题思路

由于数据范围很小,所以直接枚举所有点,判断是否可行。时间复杂度O(δX × δY),空间复杂度O(1)。

参考程序段

#include 
using namespace std;

class PointDistance {
public:
    vector <int> findPoint( int x1, int y1, int x2, int y2 );
};
int sqr(int x){ return x * x; }
vector<int> ans;
vector <int> PointDistance::findPoint(int x1, int y1, int x2, int y2) {
    ans.clear();
    for(int x = -100; x <= 100; x++)
        for(int y = -100; y <= 100; y++)
            if(sqr(x1 - x) + sqr(y1 - y) > sqr(x2 - x) + sqr(y2 - y)){
                ans.push_back(x);
                ans.push_back(y);
                return ans;
            }
    return ans;
}


TopCoder SRM 667 Div.2 T2

原题

Problem Statement

Cat Noku has just finished writing his first computer program. Noku’s computer has m memory cells. The cells have addresses 0 through m-1. Noku’s program consists of n instructions. The instructions have mutually independent effects and therefore they may be executed in any order. The instructions must be executed sequentially (i.e., one after another) and each instruction must be executed exactly once.
You are given a description of the n instructions as a vector with n elements. Each instruction is a string of m characters. For each i, character i of an instruction is ‘1’ if this instruction accesses memory cell i, or ‘0’ if it does not.
Noku’s computer uses caching, which influences the time needed to execute an instruction. More precisely, executing an instruction takes k^2 units of time, where k is the number of new memory cells this instruction accesses. (I.e., k is the number of memory cells that are accessed by this instruction but have not been accessed by any previously executed instruction. Note that k may be zero, in which case the current instruction is indeed executed in 0 units of time.)
Noku’s instructions can be executed in many different orders. Clearly, different orders may lead to a different total time of execution. Find and return the shortest amount of time in which it is possible to execute all instructions.

Definition

Class:
OrderOfOperationsDiv2
Method:
minTime
Parameters:
vector
Returns:
int
Method signature:
int minTime(vector s)
(be sure your method is public)

Limits

Time limit (s):
2.000
Memory limit (MB):
256
Stack limit (MB):
256

Constraints

n,m will be between 1 and 20, inclusive.
s will have exactly n elements.
Each element of s will have exactly m characters.
Each character of s[i] will be either ‘0’ or ‘1’ for all valid i.

Examples

0)

{
“111”,
“001”,
“010”
}
Returns: 3
Cat Noku has 3 instructions. The first instruction (“111”) accesses all three memory cells. The second instruction (“001”) accesses only memory cell 2. The third instruction (“010”) accesses only memory cell 1. If Noku executes these three instructions in the given order, it will take 3^2 + 0^2 + 0^2 = 9 units of time. However, if he executes them in the order “second, third, first”, it will take only 1^2 + 1^2 + 1^2 = 3 units of time. This is one optimal solution. Another optimal solution is to execute the instructions in the order “third, second, first”.
1)

{
“11101”,
“00111”,
“10101”,
“00000”,
“11000”
}
Returns: 9

2)

{
“11111111111111111111”
}
Returns: 400
A single instruction that accesses all 20 memory cells.
3)

{
“1000”,
“1100”,
“1110”
}
Returns: 3

4)

{
“111”,
“111”,
“110”,
“100”
}
Returns: 3

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.

解题思路

可能大家的第一反应都是每一步选花费最小来贪心,但是发现,某一步有多个花费最小时,会出问题。
我们看一组数据
0000
1100
0011
0111
如果贪心, 可能顺序是1,2,3,4, 这样答案为8, 而事实上按顺序1,3,4,2,最优,为6。
于是我们考虑DP。
首先,我们令dp[i]表示在i的二进制表示下为1的那些指令处理完毕所需的最小花费。则可以从任何二进制表示下比i少一个1的j转移过来,我们取其最小。开始状态为dp[0] = 0,结束状态为dp[(1 << n) - 1]。

参考程序段

程序中,并非枚举dp[j]向dp[i]转移,而是对于dp[j]向每个可能的dp[i]转移,并使用了类似于spfa的写法。
同时,程序中q数组保存的数指向dp数组的下标,q_used对应花费。

#include 
using namespace std;

class OrderOfOperationsDiv2 {
public:
    int minTime( vector <string> s );
};
int n;
int rec[20];
int l, r, q[1 << 23], q_used[1 << 23];
int dp[1 << 21];
int len;
int OrderOfOperationsDiv2::minTime(vector <string> s) {  
    n = s.size();
    len = s[0].size();
    for(int i = 0; i < n; i++){
        rec[i] = 0;
        for(int j = 0; j < len; j++)
            if(s[i][j] == '1') rec[i] |= (1 << j);//转成二进制方便处理
    }
    memset(dp, 255, sizeof(dp));
    dp[0] = 0;
    l = 0; r = 1; q[1] = 0; q_used[1] = 0;
    while(l < r){
        l++;
        int rec_vis = q[l];
        int rec_used = q_used[l];
        for(int i = 0; i < n; i++){//枚举可能被更新的状态
            if((rec_vis >> i) & 1) continue;
            int x = rec_vis | (1 << i);
            int y = rec_used | rec[i];
            int tt = 0;
            for(int j = 0; j < len; j++)
                if(((y >> j) & 1) == 1 && ((rec_used >> j) & 1) == 0) tt++;
            tt = tt * tt;
            if(dp[x] == -1 || dp[x] > dp[rec_vis] + tt){
                dp[x] = dp[rec_vis] + tt;
                r++;
                q[r] = x;
                q_used[r] = y;
            }
        }
    }
    return dp[(1 << n) - 1];
}

TopCoder SRM 667 Div.2 T3

原题

Problem Statement

Carol is starting a new taco shop business. She is going to open some taco shops in a block of buildings. The blocks consists of n adjacent buildings in a row. Each building has exactly m floors. The buildings are numbered 0 through n-1 in order.
Carol can open between 0 and m taco shops in each building (as there can be at most one taco shop per floor in each building). For each taco shop, the profit P[x][y] will depend on two factors:
the number x of the building that contains this taco shop
the total count y of taco shops in that particular building and in buildings adjacent to that building (including this particular taco store)
You are given the ints n and m. You are also given the profits as defined above, encoded into a vector c. For each x between 0 and n-1, and for each y between 1 and 3m, the profit P[x][y] is given in c[x*3*m+y-1].
It is guaranteed that the profits don’t increase as y increases. That is, for each valid x and y, P[x][y] will be greater than or equal to P[x][y+1]. Note that the profit is for a single store. For example, if there are three taco stores in building 7 and no other stores in buildings 6 and 8, each of these three taco stores will bring the profit P[7][3].
Determine and return the maximum total profit that Carol can gain from opening the taco shops.

Definition

Class:
ShopPositions
Method:
maxProfit
Parameters:
int, int, vector
Returns:
int
Method signature:
int maxProfit(int n, int m, vector c)
(be sure your method is public)

Limits

Time limit (s):
2.000
Memory limit (MB):
256
Stack limit (MB):
256

Constraints

n will be between 1 and 30, inclusive.
m will be between 1 and 30, inclusive.
c will have exactly n*3*m elements.
Each element of c will be between 1 and 1,000, inclusive.

For each x between 0 and n-1, the sequence c[3*m*x], c[3*m*x + 1], …, c[3*m*(x+1) - 1] will be sorted in nonincreasing order

Examples

0)

1
5
{100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 1, 1, 1, 1, 1}
Returns: 300
Carol has 1 building with 5 floors.
Building one shop will get her a profit of 100, while building two shops will get a profit of 90*2. The optimal strategy in this case is to build 5 taco shops, for a profit of 60*5=300.
1)

1
5
{1000, 5, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
Returns: 1000

2)

3
1
{
7,6,1,
10,4,1,
7,6,3
}
Returns: 14
The optimal strategy here is to open one taco store in building 0 and one taco store in building 2.
3)

2
2
{
12,11,10,9,8,7,
6,5,4,3,2,1
}
Returns: 24

4)

3
3
{
30,28,25,15,14,10,5,4,2,
50,40,30,28,17,13,8,6,3,
45,26,14,14,13,13,2,1,1
}
Returns: 127

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.

解题思路

乍一看好像很麻烦呐。看起来有后效性?仿佛不能用dp?唉?然而数据只有30?所以考虑以下乱搞?
emmm
我们还是dp,大不了扩大维数,增加状态数。嗯。我们令dp[i][j][k]表示前i幢楼,在第i幢楼这里开了j家店,同时计划在下一幢楼开k家能获得的利益。那么我们可以得到状态方程

dp[i][j][k]=max(dp[i][j][k],dp[i1][l][j]+jc[i3m+(j+k+l)1])(0<=l<=m) d p [ i ] [ j ] [ k ] = m a x ( d p [ i ] [ j ] [ k ] , d p [ i − 1 ] [ l ] [ j ] + j ∗ c [ i ∗ 3 ∗ m + ( j + k + l ) − 1 ] ) ( 0 <= l <= m )

特判一下第一栋楼和最后一栋楼。
同时注意下小细节
1、题目里并没有给出c[-1]的定义,所以任意相邻三栋楼中一定要开一家:)
2、只有一栋楼的情况:)
时间复杂度O(n^4), 空间复杂度O(n^3)【这个我觉得还是叫暴力比较好:捂脸:】

参考代码段

#include 
using namespace std;

class ShopPositions {
public:
    int maxProfit( int n, int m, vector <int> c );
};
int f[40][40][40];
int ShopPositions::maxProfit(int n, int m, vector <int> c) {
    memset(f, 0, sizeof(f));
    int ans = 0;
    for(int j = 0; j <= m; j++)//特判第一栋楼
        for(int k = 0; k <= m; k++){
            if(j + k == 0) continue;
            f[0][j][k] = max(f[0][j][k], j * c[0 * 3 * m + (j + k) - 1]);
            ans = max(ans, f[0][j][k]);
        }
    for(int i = 1; i < n - 1; i++)
        for(int j = 0; j <= m; j++)
            for(int k = 0; k <= m; k++)//O(n^4)DP
                for(int l = 0; l <= m; l++){  
                    if(j + k + l == 0) continue;
                    f[i][j][k] = max(f[i][j][k], f[i - 1][l][j] + j * c[i * 3 * m + (j + k + l) - 1]);
                    ans = max(ans, f[i][j][k]);
                }
    if(n > 1)//如果不止一栋楼,就特判最后一栋楼
    for(int j = 0; j <= m; j++)
        for(int l = 0; l <= m; l++){
            if(j + l == 0) continue;
            f[n - 1][j][0] = max(f[n - 1][j][0], f[n - 2][l][j] + j * c[(n - 1) * 3 * m + (j + l) - 1]);
            ans = max(ans, f[n - 1][j][0]);
        }
    return ans;
}

你可能感兴趣的:(TopCoder,枚举,状压DP,DP,TC题解,枚举,状压DP,DP)