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博主給我的啟發:

        

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM