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