程序设计思维与实践 Week12 作业

A - 必做题 - 1

问题描述

给出n个数,zjm想找出出现至少(n+1)/2次的数, 现在需要你帮忙找出这个数是多少?

解题思路

读入每个数并记录出现次数,没给出数据范围,所以使用map映射

代码

#include <iostream>
#include <map>
using namespace std;
map<int, int> mp;
int main(){
    int N;
    while(cin >> N){
        int temp, n = N, ans = 0;
        while(N--){
            cin >> temp;
            mp[temp]++;
            if(mp[temp] >= (n+1)/2)
                ans = temp;
        }
        cout << ans << endl;
        mp.clear();
    }
    return 0;
}

B - 必做题 - 2

问题描述

zjm被困在一个三维的空间中,现在要寻找最短路径逃生!
空间由立方体单位构成。
zjm每次向上下前后左右移动一个单位需要一分钟,且zjm不能对角线移动。
空间的四周封闭。zjm的目标是走到空间的出口。
是否存在逃出生天的可能性?如果存在,则需要多少时间?

解题思路

bfs的基本应用,从起点开始向6个方向bfs,直到终点为止。

代码

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int sx, sy, sz, ex, ey, ez;
int L, R, C;
char mp[31][31][31];
int ans[31][31][31];
bool vis[31][31][31];
int dx[] = { 0, 0, 1, -1, 0, 0 };
int dy[] = { 0, 0, 0, 0, 1, -1 };
int dz[] = { 1, -1, 0, 0, 0, 0 };
struct node {
    int x, y, z;
    node(int x, int y, int z): x(x) , y(y) , z(z) {}
};
void bfs()
{
    memset(ans, 0, sizeof(ans));
    memset(vis, 0, sizeof(vis));
    vis[sz][sx][sy] = true;
    queue<node> q;
    node tmp(sx, sy, sz);
    q.push(tmp);
    while (!q.empty()) {
        tmp = q.front();
        q.pop();
        for(int i = 0; i < 6; i++) {
            int x = tmp.x + dx[i], y = tmp.y + dy[i], z = tmp.z + dz[i];
            if(x >= 0 && x < R && y >= 0 && y < C && z >= 0 && z < L){
                if(mp[z][x][y] == '.' && !vis[z][x][y]){
                    vis[z][x][y] = true;
                    ans[z][x][y] = ans[tmp.z][tmp.x][tmp.y] + 1;
                    node tmp1(x, y, z);
                    q.push(tmp1);
                }
            }
        }
    }
    if(vis[ez][ex][ey])
        cout << "Escaped in " << ans[ez][ex][ey] << " minute(s).\n";
    else
        cout << "Trapped!\n";
}
int main()
{
    while (cin >> L >> R >> C) {
        if (L == 0 && R == 0 && C == 0)
            break;
        for (int i = 0; i < L; i++)
            for (int j = 0; j < R; j++)
                for (int k = 0; k < C; k++) {
                    cin >> mp[i][j][k];
                    if (mp[i][j][k] == 'S') {
                        sx = j;
                        sy = k;
                        sz = i;
                    } else if (mp[i][j][k] == 'E') {
                        ex = j;
                        ey = k;
                        ez = i;
                        mp[i][j][k] = '.';
                    }
                }
        bfs();
    }
    return 0;
}

C - 必做题 - 3

问题描述

东东每个学期都会去寝室接受扫楼的任务,并清点每个寝室的人数。
每个寝室里面有ai个人(1<=i<=n)。从第i到第j个宿舍一共有sum(i,j)=a[i]+…+a[j]个人
这让宿管阿姨非常开心,并且让东东扫楼m次,每一次数第i到第j个宿舍sum(i,j)
问题是要找到sum(i1, j1) + … + sum(im,jm)的最大值。且ix <= iy <=jx和ix <= jy <=jx的情况是不被允许的。也就是说m段都不能相交。
注:1 ≤ i ≤ n ≤ 1e6 , -32768 ≤ ai ≤ 32767 人数可以为负数。。。。(1<=n<=1000000)

解题思路

转移方程: d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] + a [ j ] , d p [ i − 1 ] [ k ] + a [ j ] ; ( i − 1 < k < j ) dp[i][j] = max(dp[i][j-1] + a[j], dp[i-1][k] + a[j];(i - 1 < k < j) dp[i][j]=max(dp[i][j1]+a[j],dp[i1][k]+a[j];(i1<k<j)
由于数据较大,需要使用滚动数组优化。

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
int a[1000005];
int dp[1000005];
int dp0[1000005];
int main(){
    int m, n, max;
    while(scanf("%d %d", &m, &n) != EOF){
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        memset(dp, 0, sizeof(dp));
        memset(dp0, 0, sizeof(dp0));
        for(int i = 1; i <= m; i++){
            max = -1e9;
            for(int j = i; j <= n; j++){
                dp[j] = std::max(dp[j-1] + a[j], dp0[j-1] + a[j]);
                dp0[j-1] = max;
                max = std::max(dp[j], max);
            }
        }
        printf("%d\n", max);
    }
    return 0;
}

D - 选做题 - 1

问题描述

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 ([([]])], the longest regular brackets subsequence is [([])].

解题思路

区间dp,设dp[i][j]为从i开始到j结束的区间里,最长合法括号序列。如果当前s[i]=’(’ && s[j]=’)’ 或者 s[i]=’[’ && s[j]=’]’,那么序列长度+2,dp[i][j]=dp[i+1][j-1]+2
还需要枚举k, i <= k <= j,计算dp[i][k]+dp[k][j],处理多个合法序列组合的情况

代码

#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;
int dp[105][105];
string str;
int main(){
    while(cin >> str){
        if(str == "end") break;
        memset(dp, 0, sizeof(dp));
        for(int i = str.length() - 1; i >= 0; i--){
            for(int j = i + 1; j < str.length(); j++){
                if((str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']'))
                    dp[i][j] = dp[i+1][j-1] + 2;
                for(int k = i; k <= j; k++)
                    dp[i][j] = max(dp[i][k] + dp[k][j], dp[i][j]);
            }
        }
        cout << dp[0][str.length() - 1] << endl;
    }
    return 0;
}

E - 选做题 - 2

问题描述

马上假期就要结束了,zjm还有 n 个作业,完成某个作业需要一定的时间,而且每个作业有一个截止时间,若超过截止时间,一天就要扣一分。
zjm想知道如何安排做作业,使得扣的分数最少。
Tips: 如果开始做某个作业,就必须把这个作业做完了,才能做下一个作业。

解题思路

状压dp的题。
状态S:查询S中是否有编号为i的点:S&(1<<i);在状态中添加编号为i的点:S=S | (1<<i);在状态S中删除编号为i的点:S=S ^ (1<<i)。
令f[S]表示完成S作业集合后被扣的最少分数。c[x]是作业x完成所需时间,d[x]是作业x的ddl,sum[S]是作业集合S对应的总时间,tmp=max(sum[S]+c[x]-d[x],0)是作业x被扣的分数。
转移方程:f[S | (1<<x)]=f[S] + tmp。
最后递归输出完成作业的顺序

代码

#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;
struct homework{
    string name;
    int D, C;
}hw[20];
int f[40000];
int sum[40000];
int pre[40000];
void out(int s){
    if(s == 0) return;
    out(s ^ (1 << pre[s]));
    cout << hw[pre[s]].name << endl;
}
int main(){
    int T;
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        for(int i = 0; i < n; i++)
            cin >> hw[i].name >> hw[i].D >> hw[i].C;
        sort(hw, hw + n, [](const homework &a, const homework &b){
            return a.name < b.name;
        });
        memset(f, 0x3f, sizeof(f));
        memset(sum, 0, sizeof(sum));
        f[0] = 0;
        for(int S = 0; S <= (1 << n) - 1; S++){
            for(int x = 0; x < n; x++){
                if(!(S & (1 << x))){
                    int tmp = max(sum[S] + hw[x].C - hw[x].D, 0);
                    if(f[S | (1 << x)] > f[S] + tmp){
                        f[S | (1 << x)] = min(f[S | (1 << x)], f[S] + tmp);
                        sum[S | (1 << x)] = sum[S] + hw[x].C;
                        pre[S | (1 << x)] = x;
                    }
                }
            }
        }
        cout << f[(1 << n) - 1] << endl;
        out((1 << n) - 1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值