石子合併
洛谷P1880
在一個園形操場的四周擺放N堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記爲該次合併的得分。
試設計出1個算法,計算出將N堆石子合併成1堆的最小得分和最大得分.
思路:
定義
程序代碼:
#include<iostream>
using namespace std;
int array[202];
int dp[202][202];
int dp2[202][202];
int sum[202];
int main()
{
int i, j, k, l;
int n;
cin >> n;
for(i=1; i<=n; i++)
{
cin >> array[i];
array[n + i] = array[i];
}
for(i=1; i<=2*n; i++)
{
sum[i] = sum[i-1] + array[i];
}
for(l=2; l<=n; l++) //枚舉長度爲l的區間
for(i=1; i+l-1<=2*n; i++)
{
j = i + l - 1;
dp2[i][j] = 999999999;
for(k=i; k<j; k++)
{
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);
dp2[i][j] = min(dp2[i][j], dp2[i][k] + dp2[k+1][j] + sum[j] - sum[i-1]);
}
}
int maxx = 0;
int minn = 999999999;
for(i=1; i<=n; i++)
{
if(maxx < dp[i][i+n-1])
{
maxx = dp[i][i+n-1];
}
if(minn > dp2[i][i+n-1])
{
minn = dp2[i][i+n-1];
}
}
cout << minn << endl;
cout << maxx << endl;
return 0;
}
Multiplication Puzzle
POJ 1651
The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row.
The goal is to take cards in such order as to minimize the total number of scored points.
For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring
If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be
題意:
n個數相乘,每次從中抽取一個數出來與相鄰兩個數相乘,直到抽到只剩兩個數字,第一個數和最後一個數不能抽,求和最小值。
思路:
定義
狀態轉移方程爲
程序代碼:
#include<iostream>
using namespace std;
int dp[101][101];
int array[101];
int main()
{
int n;
int i, j, k, l;
cin >> n;
for(i=1; i<=n; i++)
{
cin >> array[i];
}
for(l=3; l<=n; l++)
for(i=1; i+l-1<=n; i++)
{
j = i+l-1;
dp[i][j] = 99999999;
for(k=i+1; k<j; k++)
{
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + array[i] * array[k] * array[j]);
}
}
cout << dp[1][n] << endl;
return 0;
}
Brackets
POJ 2955
We give the following inductive definition of a “regular brackets” sequence:
the empty sequence is a regular brackets sequence,
if s is a regular brackets sequence, then (s) and [s] are regular brackets sequences, and
if a and b are regular brackets sequences, then ab is a regular brackets sequence.
no other sequence is a regular brackets sequence
For instance, all of the following character sequences are regular brackets sequences:
(), [], (()), ()[], ()[()]
while the following character sequences are not:
(, ], )(, ([)], ([(]
Given a brackets sequence of characters a1a2 … an, your goal is to find the length of the longest regular brackets sequence that is a subsequence of s. That is, you wish to find the largest m such that for indices i1, i2, …, im where 1 ≤ i1 < i2 < … < im ≤ n, ai1ai2 … aim is a regular brackets sequence.
Given the initial sequence
題意:
求一字符串括號序列的最大匹配個數。
思路:
定義
程序代碼:
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int dp[101][101];
int main()
{
int i, j, k, l;
string str;
while(1)
{
cin >> str;
memset(dp, 0, sizeof(dp));
if(str == "end")
{
break;
}
for(l=2; l<=str.length(); l++)
{
for(i=0; i+l-1<str.length(); i++)
{
j = i+l-1;
if((str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']'))
{
dp[i][j] = dp[i+1][j-1] + 2;
}
for(k=i; k<j; k++)
{
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j]);
}
}
}
cout << dp[0][str.length()-1] << endl;
}
return 0;
}
Brackets Sequence
POJ 1141
Let us define a regular brackets sequence in the following way:
- Empty sequence is a regular sequence.
- If S is a regular sequence, then (S) and [S] are both regular sequences.
- If A and B are regular sequences, then AB is a regular sequence.
For example, all of the following sequences of characters are regular brackets sequences:
(), [], (()), ([]), ()[], ()[()]
And all of the following character sequences are not:
(, [, ), )(, ([)], ([(]
Some sequence of characters ‘(‘, ‘)’, ‘[‘, and ‘]’ is given. You are to find the shortest possible regular brackets sequence, that contains the given character sequence as a subsequence. Here, a string a1 a2 … an is called a subsequence of the string b1 b2 … bm, if there exist such indices 1 = i1 < i2 < … < in = m, that aj = bij for all 1 = j = n.
題意:
增加最少的括號使給定的括號序列匹配。
思路:
定義
枚舉k位置,每次更新dp值時將
採用遞歸打印
若
若
程序代碼:
#include<iostream>
#include<string>
using namespace std;
string str;
int dp[101][101];
int dp2[101][101];
void print(int l, int r)
{
if(l == r){
if(str[l] == '(' || str[l] == ')'){
cout << "()";
}
else if(str[l] == '[' || str[r] == ']'){
cout << "[]";
}
return;
}
if(l > r){
return;
}
if(dp2[l][r] < 0){
cout << str[l];
print(l+1, r-1);
cout << str[r];
}
else{
int k = dp2[l][r];
print(l, k);
print(k+1, r);
}
}
int main()
{
int i, j, k, l;
cin >> str;
for(l=2; l<=str.length(); l++)
for(i=0; i+l-1<str.length(); i++)
{
j = i+l-1;
if((str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']'))
{
dp[i][j] = dp[i+1][j-1] + 2;
dp2[i][j] = -1;
}
for(k=i; k<j; k++)
{
if(dp[i][j] <= dp[i][k] + dp[k+1][j])
{
dp[i][j] = dp[i][k] + dp[k+1][j];
dp2[i][j] = k;
}
}
}
print(0, str.length()-1);
cout << "\n";
return 0;
}
You Are the One
hdu 4283
The TV shows such as You Are the One has been very popular. In order to meet the need of boys who are still single, TJUT hold the show itself. The show is hold in the Small hall, so it attract a lot of boys and girls. Now there are n boys enrolling in. At the beginning, the n boys stand in a row and go to the stage one by one. However, the director suddenly knows that very boy has a value of diaosi D, if the boy is k-th one go to the stage, the unhappiness of him will be (k-1)*D, because he has to wait for (k-1) people. Luckily, there is a dark room in the Small hall, so the director can put the boy into the dark room temporarily and let the boys behind his go to stage before him. For the dark room is very narrow, the boy who first get into dark room has to leave last. The director wants to change the order of boys by the dark room, so the summary of unhappiness will be least. Can you help him?
題意:
有一個隊列,每個人有一個憤怒值D,如果他是第K個上場,不開心指數就爲(K-1)*D。但是邊上有一個小黑屋(其實就是個堆棧),可以一定程度上調整上場程序,求憤怒值和最小值。
思路:
定義
若第i個人第k個上場,
其中
程序代碼:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stdio.h>
using namespace std;
#define LL long long
LL dp[103][103];
LL array[103];
LL sum[103];
int main()
{
//freopen("tt.in", "r", stdin);
//freopen("xx1.out", "w", stdout);
int t, n;
int i, j, k, l, kk;
cin >> t;
for(kk=1; kk<=t; kk++)
{
cin >> n;
memset(dp, 0, sizeof(dp));
for(i=1; i<=n; i++)
{
cin >> array[i];
sum[i] = sum[i-1] + array[i];
}
for(l=2; l<=n; l++)
for(i=1; i+l-1<=n; i++)
{
j = i+l-1;
dp[i][j] = (l-1)*array[i] + dp[i+1][j]; //設初始值
for(k=1; k<=l; k++)
{
dp[i][j] = min(dp[i][j], dp[i+1][i+k-1] + array[i] * (k-1) +
dp[i+k][j] + (sum[j] - sum[i+k-1]) * k);
}
}
cout << "Case #" << kk << ": " << dp[1][n] << endl;
}
}
String painter
hdu2476
There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can change a segment of characters of a string to any other character you want. That is, after using the painter, the segment is made up of only one kind of character. Now your task is to change A to B using string painter. What’s the minimum number of operations?
題意:
求從A字串到B字串需要的最小步驟,每一步驟可以將一段字串變爲同一字母字串
思路:
分兩步。
定義dp[i][j] 爲空字串到B字串需要的最小步驟,
設初值dp[i][j]=dp[i+1][j]+1 , 當前目標爲i,枚舉kϵ[i+1,j] ,若strB[i]=strB[k] ,表示可將i~k變爲一種字母,之後處理dp[i+1][k]
狀態轉移方程爲:dp[i][j]=min(dp[i+1][k]+dp[k+1][j]) 定義dp2[i] 爲A字串到B字串0~i序列的最小步驟,
設初值dp2[i]=dp[0][i] , 若strA[i]=strB[j],則dp2[i]=dp2[i−1] ,
狀態轉移方程:dp2[i]=min(dp2[j]+dp[j+1][i])
程序代碼:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int dp[102][102];
int dp2[102];
int main()
{
string str1, str2;
int i, j, k, l;
while(cin >> str1 >> str2)
{
memset(dp, 0, sizeof(dp));
memset(dp2, 0, sizeof(dp2));
for(i=0; i<str2.length(); i++){
dp[i][i] = 1;
}
for(l=2; l<=str2.length(); l++)
{
for(i=0; i<str2.length(); i++)
{
j = i+l-1;
dp[i][j] = dp[i+1][j] + 1;
for(k=i+1; k<=j; k++)
{
if(str2[i] == str2[k])
{
dp[i][j] = min(dp[i][j], dp[i+1][k] + dp[k+1][j]);
}
}
}
}
for(i=0; i<str1.length(); i++)
{
dp2[i] = dp[0][i];
if(i == 0){
if(str1[i] == str2[i])
{
dp2[i] = 0;
}
else{
dp2[i] = 1;
}
}
else {
if(str1[i] == str2[i])
{
dp2[i] = dp2[i-1];
}
else{
for(j=0; j<i; j++)
{
dp2[i] = min(dp2[i], dp2[j] + dp[j+1][i]);
}
}
}
}
cout << dp2[str1.length()-1] << endl;
}
return 0;
}