week11(复习1)

11-1 汤姆斯的天堂梦

题目链接

P1796

解题思路

简单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 跑步

题目链接

P1806

解题思路

用 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 砝码称重

题目链接

P8742

解题思路

对于每个砝码,都有三种情况,可以视为[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 遗址

题目链接

P1959

解题思路

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 环境治理

题目链接

P8794

解题思路

二分+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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值