A.Shortest path of the king
题目大意:
- 有一个棋盘(x: A-H,y:1-8),棋子可以向与其所在位置有公共顶点的其他位置走动,求从起点到终点的最少步数和路径。
Input
a8
h1
Output:
7
RD
RD
RD
RD
RD
RD
RD
思路:
- 尽量斜着走,注意考虑边界
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
int main()
{
string from, to;
cin >> from >> to;
vector<string> path;
path.clear();
string now = from;
while (now != to)
{
if (to[0] > now[0] && to[1] < now[1])
{
path.push_back(string("RD"));
now[0] += 1;
now[1] -= 1;
}
else if (to[0] > now[0] && to[1] > now[1])
{
path.push_back(string("RU"));
now[0] += 1;
now[1] += 1;
}
else if (to[0] < now[0] && to[1] > now[1])
{
path.push_back(string("LU"));
now[0] -= 1;
now[1] += 1;
}
else if (to[0] < now[0] && to[1] < now[1])
{
path.push_back(string("LD"));
now[0] -= 1;
now[1] -= 1;
}
else if (to[0] < now[0])
{
path.push_back(string("L"));
now[0] -= 1;
}
else if (to[0] > now[0])
{
path.push_back(string("R"));
now[0] += 1;
}
else if (to[1] > now[1])
{
path.push_back(string("U"));
now[1] += 1;
}
else if (to[1] < now[1])
{
path.push_back(string("D"));
now[1] -= 1;
}
}
int size = path.size();
cout << size << endl;
for (int i = 0; i < size; i++)
cout << path[i] << endl;
return 0;
}
B. Lorry
题目大意:
- 有一个卡车容积为 v v v,有2种船,皮划艇(kayak) i i i占面积为1,可承载力为 p i p_i pi,双体船(catamaran) j j j占面积为2,可承载力为 p j p_j pj。最后求该卡车应该选择运哪些船使得这些船所占空间不大于 v v v,且可承载力最大。
输入:
- n n n为船数量, v v v为卡车容积。 ( 1 ≤ n ≤ 1 0 5 ; 1 ≤ v ≤ 1 0 9 ) (1 ≤ n ≤ 10^5; 1 ≤ v ≤ 10^9) (1 ≤ n ≤ 105;1 ≤ v ≤ 109)
- 输入n行,每行为船的类型 t i t_i ti和可承载力 p i p_i pi。 ( 1 ≤ t i ≤ 2 ; 1 ≤ p i ≤ 1 0 4 ) (1 ≤ t_i ≤ 2; 1 ≤ p_i ≤ 10^4) (1 ≤ ti ≤ 2;1 ≤ pi ≤ 104). 1为kayak,2为catamaran
输出:
- 最后的最大的可承载力
- 选择了哪些船
思路:
- 版本1:按照
capacity/type
从大到小排序,然后每次选择最大的。但是考虑到这样一个问题,就是最后剩下1。这种情况就可以放弃一个1选择1个2。这样改了之后代码还是不对。这样考虑很难考虑全,代码不好写。 - 最终版:
- 考虑 特殊情况: 当 v v v为奇数时,那个体积为1且可承载力最大的kayak是一定会被选择的。可以先进行选择,注意这里kayak可能数量为0
- 剩下情况: 将体积为1的两两相加,相加后的值去和原本体积为2的比,然后每次选择较大的那个即可。
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <unordered_set>
using namespace std;
struct Node
{
int id1;
int id2;
int capacity;
};
vector<Node> boat;
vector<Node> kayak;
vector<int> choose;
bool cmp(const Node& A, const Node& B)
{
return A.capacity > B.capacity;
}
int main()
{
int n, v;
cin >> n >> v;
boat.clear();
kayak.clear();
choose.clear();
int type, capa;
Node tmp;
for (int i = 1; i <= n; i++)
{
cin >> type >> capa;
tmp.id1 = i;
tmp.id2 = -1;
tmp.capacity = capa;
if (type == 1)
kayak.push_back(tmp);
else
boat.push_back(tmp);
}
sort(kayak.begin(), kayak.end(), cmp);
int res = 0;
int start = 0;
int sizeK = kayak.size();
if ((v & 1) && (sizeK > 0))
{
v -= 1;
res += kayak[0].capacity;
choose.push_back(kayak[0].id1);
start++;
}
for (int i = start; i < sizeK; i += 2)
{
if (i + 1 < sizeK)
{
tmp.id1 = kayak[i].id1;
tmp.id2 = kayak[i+1].id1;
tmp.capacity = kayak[i].capacity + kayak[i+1].capacity;
}
else if (i + 1 == sizeK)
{
tmp = kayak[i];
}
boat.push_back(tmp);
}
sort(boat.begin(), boat.end(), cmp);
int sizeB = boat.size();
for (int i = 0; i < sizeB; i++)
{
if (v < 2)
break;
v -= 2;
res += boat[i].capacity;
choose.push_back(boat[i].id1);
choose.push_back(boat[i].id2);
}
cout << res << endl;
for (int i = 0; i < choose.size(); i++)
if (choose[i] != -1)
cout << choose[i] << " ";
cout << endl;
return 0;
}
C. Tic-tac-toe
题目大意:
- 3 * 3的棋盘,2个人相互放棋子,谁先达到3个成行,成列或对角线即为赢。给出现在棋局,判断现在情况。
不同情况:
假设A先手,B后手
- legal: A和B的相差数量始终在(0,1)之间。若有人赢了,立刻结束比赛。棋盘上只有可能一个人的棋子摆放完成。
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <set>
#include <unordered_set>
using namespace std;
char m[5][5];
typedef pair<int, int> pii;
vector<pii> one, two;
bool oneLine(vector<pii>A)
{
if (A[0].first + A[2].first == 2 * A[1].first && A[0].second + A[2].second == 2 * A[1].second)
return true;
return false;
}
bool judgeOK(int sizeX, vector<pii> v)
{
vector<pii> tmp;
int total = (1 << sizeX);
bool line = false;
int num;
for (int i = 0; i < total; i++)
{
tmp.clear();
num = 0;
for (int j = 0; j < sizeX; j++)
{
if (((1 << j) & i) != 0)
{
num++;
tmp.push_back(v[j]);
}
}
if (num == 3)
line = oneLine(tmp);
if (line)
return true;
}
return false;
}
int main()
{
for (int i = 0; i < 3; i++)
scanf("%s", m[i]);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
if (m[i][j] == 'X')
one.push_back(make_pair(i, j));
else if (m[i][j] == '0')
two.push_back(make_pair(i, j));
}
int sizeX = one.size();
int size0 = two.size();
sort(one.begin(), one.end());
sort(two.begin(), two.end());
string res;
string oneOK = "", twoOK = "";
if (size0 > sizeX || sizeX - size0 >= 2)
res = "illegal";
else
{
if (sizeX >= 3)
{
bool line = judgeOK(sizeX, one);
if (line)
oneOK = "the first player won";
}
if (size0 >= 3)
{
bool line = judgeOK(size0, two);
if (line)
twoOK = "the second player won";
}
if (oneOK != "" && sizeX == size0)
res = "illegal";
else if (twoOK != "" && sizeX > size0)
res = "illegal";
else if (oneOK != "")
res = oneOK;
else if (twoOK != "")
res = twoOK;
else if (sizeX == size0)
res = "first";
else if (sizeX + size0 == 9)
res = "draw";
else if (sizeX > size0)
res = "second";
}
cout << res << endl;
return 0;
}
D.Least Cost Bracket Sequence
题目大意:
- 给一串括号的序列,该包含
(
,)
和?
。然后将?
替换成(
或者)
, 使得该序列成为一个常规的括号序列。 - 对于每个
?
,给出用(
,)
替换的成本,在所有可能的情况中,选择成本最低的。
输入:
- 一行包含偶数长度的非空模式,由
(
,)
和?
组成,长度不超过 5 ⋅ 1 0 4 5 \cdot 10^4 5⋅104 。其中?
个数为 m m m个 - 输入
m
m
m行,
a
i
,
b
i
(
1
≤
a
i
,
b
i
≤
1
0
6
)
a_i , b_i (1 ≤ a_i, b_i ≤ 10^6)
ai,bi(1 ≤ ai, bi ≤ 106),
a
i
a_i
ai为替换成
(
的成本, b i b_i bi为替换成)
的成本
输出:
- 最低成本(若没有方案则输出-1)
- 替换后的括号序列
input:
(??)
1 2
2 8
output:
4
()()
思路:
- 我不太会,想到唯一判断括号序列合法性的是用栈。所以百度了一下……
- 判断序列合法性:一个前缀和
s
u
m
sum
sum,遇到
(
就+1,遇到)
就-1。在遍历序列中整个过程不存在 s u m < 0 sum<0 sum<0 且最后 s u m = 0 sum=0 sum=0 则该括号序列为合法。 - 贪心:先假设所有
?
都是)
,当碰到 s u m < 0 sum<0 sum<0的情况时判断前方是否有?
可以替换成(
。如果没有,则直接判不合法,否则选择使成本最低的替换成(
。 - 如何选择使最后成本最低:选择
left - right
最小的,这个值表示了由? -> ) -> (
后一步过程可以减少的最大值(前一步每个都要经历)。而这一步使用优先队列实现。 - 注意:优先队列默认top为最大,重载
<
时函数内要用>
;注意数值范围,int
大概 1 0 9 10^9 109,这里超了,用long long
- 总结:好像是我没碰到过的贪心套路……get了一点不过好像不太明白为什么。就是贪心那里为什么就全都替换成
)
,我知道替换成(
不对,可是以后碰到类似情况可能递推不来。
代码:
#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long llong;
struct Node
{
int id;
int left;
int right;
friend bool operator < (const Node& A, const Node& B)
{
return (A.left - A.right) > (B.left - B.right);
}
};
int main()
{
string str;
while (cin >> str)
{
vector<int> id;
int cnt = 0;
for (size_t i = 0; i < str.length(); ++i)
{
if (str[i] == '?')
{
++cnt;
id.push_back(i);
}
}
vector<Node> vec;
Node tmp;
for (size_t i = 0; i < cnt; ++i)
{
cin >> tmp.left >> tmp.right;
tmp.id = i;
vec.push_back(tmp);
}
int sum = 0;
llong res = 0;
cnt = -1;
priority_queue<Node> pq; //increase order
for (size_t i = 0; i < str.length(); ++i)
{
if (str[i] == '(')
sum += 1;
else if (str[i] == ')')
sum -= 1;
else
{
++cnt;
pq.push(vec[cnt]);
res += vec[cnt].right;
sum -= 1;
str[i] = ')';
}
if (sum < 0 && pq.empty())
break;
else if (sum < 0)
{
Node tmp = pq.top();
pq.pop();
res += tmp.left - tmp.right;
str[id[tmp.id]] = '(';
sum += 2;
}
}
if (sum != 0)
res = -1;
cout << res << endl;
if (res != -1)
cout << str << endl;
}
return 0;
}