11-1 汤姆斯的天堂梦
题目链接
解题思路
简单DP,f[i][j] 表示到达等级为 i 编号为 j 的星球所需最小费用,递推式即为f[i][j]=min(f[i][j],f[i-1][fr]+w)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int n;
int k[maxn];
int f[maxn][maxn];
int main(){
cin>>n;
memset(f,0x3f,sizeof(f));
f[0][1]=0;
for (int i=1; i<=n; i++){
cin>>k[i];
for (int j=1; j<=k[i]; j++){
int tmp;
int fr,w;
cin>>tmp;
while (tmp){
cin>>w;
fr=tmp;
f[i][j]=min(f[i][j],f[i-1][fr]+w);
cin>>tmp;
}
}
}
int ans=INT_MAX;
for (int i=1; i<=k[n]; i++){
ans=min(ans,f[n][i]);
}
cout<<ans;
return 0;
}
11-2 跑步
题目链接
解题思路
用 01 背包去想,问题转化成一共有 n - 1 个物品,重量和价值都分别是 1 , 2 , 3 … n - 1,去填容量为 n 的背包,求方案数。可得递推式 f[j] += f[j-i]。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e2+5;
typedef long long ll;
ll f[maxn];
int n;
ll ans;
int a[maxn];
int main() {
cin >> n;
f[0] = 1;
for (int i = 1; i <= n - 1 ; i ++){
for (int j = n; j >= i; j --){
f[j] += f[j-i];
}
}
cout << f[n];
return 0;
}
11-3 砝码称重
题目链接
解题思路
对于每个砝码,都有三种情况,可以视为[j] [j+a[i]] [abs(j-a[i])],然后用01背包。
注意: maxm=2e5+5,要比题目要求的背包大小大一倍,因为推导的过程中可能会超过其大小。枚举背包容量的循环,注意要从0开始,否则会有遗漏。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+5,maxm=2e5+5;
int n;
int a[maxn];
int sum;
bool f[maxn][maxm];
int main(){
cin>>n;
for (int i=1; i<=n; i++){
cin>>a[i];
sum+=a[i];
}
f[0][0]=1;
for (int i=1; i<=n; i++){
for (int j=0; j<=sum; j++){
f[i][j]=f[i-1][abs(j-a[i])] || f[i-1][j] || f[i-1][j+a[i]];
}
}
int ans=0;
for (int i=1; i<=sum; i++){
ans+=f[n][i];
}
cout<<ans;
return 0;
}
11-4 遗址
题目链接
解题思路
set 存储每个点的信息,并进行自动排序。枚举一个点时,只需再枚举另一个点,就可以确定正方形剩下的两个点坐标。
因为其中大量STL使用,如果不开o2就TLE了。
如果不用STL,可以用vis数组去记录某一点是否为柱子,不过要注意判断的时候数组不要越界。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e3 + 5;
struct node
{
int x, y;
} a[maxn];
int n;
bool vis[5005][5005];
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i].x >> a[i].y;
vis[a[i].x][a[i].y] = 1;
}
sort(a + 1, a + 1 + n, [](node a, node b)
{ return (a.y < b.y || (a.y == b.y && a.x < b.x)); });
int s = 0;
for (int i = 1; i <= n; i++)
{
int x = a[i].x, y = a[i].y;
for (int j = i + 1; j <= n; j++)
{
int dx = a[j].x, dy = a[j].y;
if (x + y - dy >= 0 && x + y - dy <= maxn && dx - dy + y >= 0 && dx - dy + y <= maxn)
if (dx - x + y >= 0 && dx - x + y <= maxn && dx + dy - x >= 0 && dx + dy - x <= maxn)
if (vis[x + y - dy][dx - x + y] && vis[dx - dy + y][dx + dy - x])
{
s = max(s, (x - dx) * (x - dx) + (y - dy) * (y - dy));
}
}
}
cout << s;
return 0;
}
11-5 环境治理
题目链接
解题思路
二分+Floyd最短路
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
int f[maxn][maxn], a[maxn][maxn], d[maxn][maxn];
int n, p;
int main()
{
cin >> n >> p;
int l = 0, r = -1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> a[i][j];
r = max(r, a[i][j]);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> d[i][j];
}
}
int ans = -1;
while (l <= r)
{
int mid = l + r >> 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
f[i][j] = a[i][j];
for (int i = 1; i <= n; i++)
{
int s = mid / n;
if (mid % n >= i)
s++;
for (int j = 1; j <= n; j++)
{
f[i][j] -= s;
f[j][i] -= s;
if (f[i][j] < d[i][j])
f[i][j] = d[i][j];
if (f[j][i] < d[j][i])
f[j][i] = d[j][i];
}
}
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
int cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cnt += f[i][j];
if (cnt > p)
{
l = mid + 1;
}
else
{
ans = mid;
r = mid - 1;
}
}
cout << ans;
return 0;
}