CCF201809-4 再卖菜

问题描述:

 

AC代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<map>
 5 #include<set>
 6 #include<vector>
 7 #include<algorithm>
 8 #include<cmath>
 9 #include<fstream>
10 #include<iomanip>
11 #include<queue>
12 #include<unordered_set>
13 using namespace std;
14 typedef long long ll;
15 typedef unsigned long long ull; 
16 const ll maxn = 300 + 5;
17 int target;
18 
19 int num = 1;
20 
21 int a[maxn], b[maxn];
22 bool f[maxn][maxn][maxn];
23 
24 void dfs(int n, int x, int y){
25     if(f[n][x][y])return;
26     f[n][x][y] = true;
27     if(n == target - 1){
28         for(int i = 0; i <= 2; i++){
29             if((3 * a[n] - b[n - 1] + i) / 2 == a[n + 1]){//原等式 应为 2 * a[n + 1] (+1) = 3 * a[n] - b[n - 1](+1) (+2)  其中括号为可选项,代码里左边等式的 +1 消失了是因为有 /2 的存在。 
30                 b[n + 1] = 3 * a[n] - b[n - 1] - b[n] + i;
31                 for(int i = 1; i <= target; i++){
32                     cout << b[i] << " ";
33                 }
34                 exit(0);
35             }
36         }
37     }
38     for(int i = 0; i < 3; i++){
39         b[n + 1] = 3 * a[n] - b[n] - b[n - 1] + i;
40         if(b[n + 1] >= 1)dfs(n + 1, y, b[n + 1]);
41     }
42     return;
43 }
44 
45 
46 int main(){
47 //    ios::sync_with_stdio(false);
48 //    ifstream cin("data.txt");
49 //    freopen("data.txt", "r", stdin);
50     memset(f, false, sizeof(f));
51     int n;
52     cin >> n;
53     target = n;
54     for(int i = 1; i <= n; i++){
55         cin >> a[i];
56     }
57     for(int i = 1; i <= 2 * a[1]; i++){
58         b[1] = i;
59         if(i != 2 * a[1]){
60             b[2] = 2 * a[1] - i;
61             dfs(2, b[1], b[2]);
62         }
63         b[2] = 2 * a[i] - i + 1;
64         dfs(2, b[1], b[2]);
65     }
66     return 0;
67 }

我想说的:

   很菜很菜的我在绝望搜题解之前是懵逼的,搜了几篇题解都是 差分约束 的解法,然而,看到了这篇博客  https://blog.csdn.net/imotolove/article/details/82777819 ,让我眼前一亮!对啊,可以暴力的啊!

   我们的思路就是:

   假设 b[] 为所求 a[] 为已知。
   我们把不等式写出来可以得到递推式:3 * a[n] <= b[n + 1] + b[n - 1] + b[n] <= 3 * a[n] + 2
   即, 我们知道 b[n - 1]、 b[n] 时 只需枚举 0, 1, 2即可得到 b[n + 1]
   对于起始和结束的特殊情况, 改写上式。

   对于起始的 b[1] 和 b[2], 我们知道 2 * a[1] <= b[1] + b[2] <= 2 * a[1] + 1
   即我们只需从 1 到 2 * a[1]枚举 b[1] 即可确定 两个初值
   对于最后的值 b[target] , 我们需保证 同时 满足 两个式子 才能 确定最后一个值

   对于 dfs的有效性:
   我们按递推式去推 b[],若可以推出来,则一定符合题意(因为递推式是满足题意的),
   否则,中间某值出现小于 1 的情况 或者 最后的值不符合两个不等式,都会记忆下然后退出来。
   每次碰到之前记忆过得情况时,直接退出, 因为之前通过这条路走不通没必要浪费时间。

   对于字典序的解释:
   我们是依次从小到大从前往后搜的,所以第一次满足题意的解 也 一定满足了字典序最小的要求。

 

   最后再鸣谢一下这位CSDN博主给我的启发:

        

 

转载于:https://www.cnblogs.com/peichaoL/p/10467602.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值