8.16考试总结

今天与提高组的几位大佬一起打了一场比赛,发现考题竟然是原题!(于是拿了400分

这些大佬还是比我强多了

A - Buns

这道题首先强调一点做糕点的顺序不会改变答案!
所以我们就可以按顺序来
首先做第0种的白面糕点,然后做第1种,2种……m种
第i种最多做 [ a i b i ] [\frac{a_i}{b_i}] [biai]个,所以0,1背包跑这么多遍即可
白面糕点最多可做 [ n c 0 ] [\frac{n}{c_0}] [c0n]个,枚举即可
为了不要浪费 d p i dp_i dpi表示恰好用i克面团的最大收益
所以要重头到尾再扫一遍

#include<bits/stdc++.h>
using namespace std;
int n,m,a,b,c,d,dp[1010],ans;
int main(){
	cin>>n>>m>>c>>d;
	for(int i=1;i<=n/c;i++)dp[i*c]=i*d;
	while(m--){
		cin>>a>>b>>c>>d;
		for(int t=1;t<=a/b;t++){
			for(int i=n;i>=c;i--){
				dp[i]=max(dp[i],dp[i-c]+d);
			}
		}
	}
	for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
	cout<<ans;
	return 0;
}

C - Petya and Spiders

这道题我用非常(奇怪)有趣的方法做了出来
别急,先来分析一下数据范围
1 < = n , m < = 40 , n ∗ m < = 40 1<=n,m<=40,n*m<=40 1<=n,m<=40,nm<=40
不难发现 m i n ( n , m ) < = 6 min(n,m)<=6 min(n,m)<=6
于是我就有了大胆的想法——“DFS“

第一次翻车如下

如果每一只蜘蛛dfs五个方向的话,不难发现,复杂度达到了
O ( 5 n ∗ m ) , n ∗ m < = 40 O(5^{n*m}),n*m<=40 O(5nm),nm<=40
5的40次方高达9094947017729282379150390625直接TLE

第二次成功=dfs+最优性剪枝+(我自认为的玄学优化)

由于周老师教过我正难则返的思想,既然不能直接正面枚举 n ∗ m n*m nm只蜘蛛,那就枚举蜘蛛的聚集点
由于每个聚点周围的蜘蛛都会来到这个聚点,于是时间复杂度就以常数级别降了下来(我认为的玄学所在)

具体思路

首先, s p i d e r i , j spider_{i,j} spideri,j记录 i , j i,j i,j点是否还有蜘蛛,如果有,记录当前点的坐标,然后向五个方向 f o r for for一遍(上,下,左,右和他本身)并将这五个点定为聚点,将聚点五个方向的蜘蛛聚过来,然后dfs下一层 特别提醒:注意回溯 特别提醒:注意回溯 特别提醒:注意回溯

code
#include <bits/stdc++.h>
using namespace std;
struct node {
  int x, y;
};
int n, m;
int ans;
bool spider[100][100];
int dx[5] = {1, -1, 0, 0, 0};
int dy[5] = {0, 0, 1, -1, 0};
void dfs(int x) {
  int xx, yy;
  bool flag = 0;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (spider[i][j]) {
        xx = i;
        yy = j;
        flag = 1;//找到一个还有蜘蛛的点
      }
    }
    if (flag) break;
  }
  if (!flag) {
    ans = min(ans, x);//统计答案求出最少聚点数,最后(n*m)-ans即为最大空白数
    return;
  }
  if (x + 1 >= ans) return;//最优性剪枝
  for (int i = 0; i < 5; i++) {
    int nx = xx + dx[i];
    int ny = yy + dy[i];//聚点
    if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
    queue<node> q;
    for (int k = 0; k < 5; k++) {
      if (spider[nx + dx[k]][ny + dy[k]]) {
        spider[nx + dx[k]][ny + dy[k]] = 0;//聚点周围的蜘蛛全部走过来
        node tmp;
        tmp.x = nx + dx[k], tmp.y = ny + dy[k];
        q.push(tmp);
      }
    }
    dfs(x + 1);
    while (!q.empty()) {//记得回溯!!!
      spider[q.front().x][q.front().y] = 1;
      q.pop();
    }
  }
}
int main() {
  cin >> n >> m;
  ans = n * m;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      spider[i][j] = 1;
    }
  }
  dfs(0);
  cout << n * m - ans;
  return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值