中国计量大学现代科技学院第四届“中竞杯”程序设计校赛(同步赛)
题目链接:https://ac.nowcoder.com/acm/contest/9680#question
题目描述: https://ac.nowcoder.com/acm/contest/9680/F
样例
输入:
2 3
2 3 2
4 1 4 1 5
输出:
10
解释:两层中选3个,最大价值为10
只需要知道每一层中选i个的最大价值是多少,然后通过上一层选j个的最大值,转移到此层来,
也就类似于背包的转移,至于每一层选i个的最大值,就是暴力枚举一下,左边选x个,右边选i-x个的最大值是多少即可求出每一层选i个的最大值是多少
#include <bits/stdc++.h>
using namespace std;
const int N = 110,M = 11000;
int dp[N][M]; // N层,每层最多选的个数是多少
int sum[N][N]; // 记录每一层选i个的最大值是多少,第一维是层数,第二维是几个
int a[N][N];
int n,m,c,x;
int pre[N]; // 前缀
int suf[N]; // 后缀
void solve(int l)
{
for(int i = 1;i <= x;i ++)
pre[i] = pre[i - 1] + a[l][i];
for(int i = x;i >= 1;i --)
suf[i] = suf[i + 1] + a[l][i];
for(int i = 0;i <= x;i ++){
for(int j = 0;j + i <= x;j ++){
sum[l][i + j] = max(pre[i] + suf[x - j + 1],sum[l][i + j]);
}
}
for(int i = 0;i <= m;i ++)
{
dp[l][i] = dp[l - 1][i];
for(int j = 0;j <= x;j ++)
{
if(i >= j)
dp[l][i] = max(dp[l - 1][i - j] + sum[l][j],dp[l][i]);
}
}
}
int main()
{
cin >> n >> m;
for(int i = 1;i <= n;i ++)
{
cin >> x;
for(int j = 1;j <= x;j ++)
cin >> a[i][j];
solve(i);
}
cout << dp[n][m] << endl;
return 0;
}
题目描述 https://ac.nowcoder.com/acm/contest/9680/I
样例1
输入:
3 3 0 0 2 2
000
110
110
输出
1
样例2
输入:
3 3 0 0 2 2
001
101
100
输出
2
解释样例1:最开始的时候方向为向右,然后到达1,3的时候改变方向,所以方向只改变了一次,答案输出1
这个题考察的是简单的bfs,也就是再处理方向入队的时候比较难处理,让当前这个点入队的情况有两种1、当前这个点的方向和之前的方向不一样并且当前这个点到原点的距离通过它前一个点改变方向后的距离远,那么这个点就得入队.2、当前这个点的方向和之前点的方向一样,但是当前这个点比之前的点离原点远,那么这个点就得入队,并且更新距离;
#include <bits/stdc++.h>
using namespace std;
const int N = 5100;
int n,m,sx,sy,ex,ey;
char g[N][N];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};
bool check(int x,int y)
{
if(x < 0 || x >= n || y < 0 || y >= m){
return false;
}
if(g[x][y] == '1') return false;
return true;
}
int dist[N][N];
bool st[N][N];
struct node{
int x,y,dis,where;
};
void bfs()
{
for(int i = 0;i < n;i ++)
for(int j = 0;j < m;j ++)
dist[i][j] = 0x3f3f3f3f;
queue<node>q;
q.push({sx,sy,0,-1});
while(q.size())
{
auto t = q.front();
q.pop();
int x = t.x,y = t.y,dis = t.dis,where = t.where;
for(int i = 0;i < 4;i ++)
{
int a = x + dx[i],b = y + dy[i];
if(check(a,b)){
if(i != where && where != -1){
if(dist[a][b] >= dis + 1){
dist[a][b] = dis + 1;
q.push({a,b,dist[a][b],i});
}
}else{
if(dist[a][b] >= dis){
dist[a][b] = dis;
q.push({a,b,dist[a][b],i});
}
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m >> sx >> sy >> ex >> ey;
for(int i = 0;i < n;i ++)
cin >> g[i];
int mm = 0x3f3f3f3f;
bfs();
mm = min(mm,dist[ex][ey]);
if(mm > 0x3f3f3f3f / 2) mm = -1;
cout << mm << endl;
return 0;
}
这个代码忘记是哪位大神写的了。。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fast_io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
const int INF = INT_MAX;
const int N = 5005;
char mp[N][N];
int ans[N][N];
//方向数组
int dx[4] = {1,0,-1,0};
int dy[4] = {0,1,0,-1};
int n, m, sx, sy, ex, ey;
struct point
{
int x, y, cnt_turn, dir;
};
bool check(int x, int y) {
if(0 <= x && x < n && 0 <= y && y < m && mp[x][y] == '0')
return true;
return false;
}
queue<point> q;
void bfs() {
q.push((point) {sx, sy, 0, -1});//-1表示第一次移动不算转弯
while(!q.empty()) {
point cur = q.front();
q.pop();
int pre_x = cur.x, pre_y = cur.y, pre_d = cur.dir;
for(int i = 0; i < 4; i++) {
int cur_x = cur.x + dx[i], cur_y = cur.y + dy[i];
//判断当前点是不是可以走
if(check(cur_x, cur_y)) {
int cur_ct = cur.cnt_turn;//到达当前点的转弯次数
//1.如果上次移动方向(nd)与当前移动方向(i)不同
//2.且上一个点不是起点
//则转弯次数(n_ct)加一
if(pre_d != i && pre_d != -1) {
cur_ct++;
}
//如果能转更少的弯走到该点,则更新到达此点的最少转弯次数
//并把该点压进队列
if(ans[cur_x][cur_y] >= cur_ct) {
ans[cur_x][cur_y] = cur_ct;
q.push((point){cur_x, cur_y, cur_ct, i});
}
}
}
}
}
int main()
{
fast_io;
fill(ans[0], ans[0] + N * N, INF);
cin >> n >> m >> sx >> sy >> ex >> ey;
for(int i = 0; i < n; i++) {
cin >> mp[i];
}
bfs();
if(ans[ex][ey] == INF) cout << -1 << endl;
else cout << ans[ex][ey] << endl;
}
知足常乐!