近鄰取樣插值方法縮放BGRA圖片資料
阿新 • • 發佈:2022-05-12
練習一下區間dp,總結一下題型
括號配對問題 Brackets Sequence
連結:https://172.16.79.125/contest/view.action?cid=831#problem/A
題意:給一串括號序列。依照合法括號的定義,加入若干括號,使得序列合法。
一道典題,思路是括號配對加上路徑回溯,找出輸入的所有不配對單括號,在輸出時將其補充成完整括號對即可
括號配對
求序列配對的括號量,使用三層迴圈,前兩層列舉長度和起點,然後要注意括號配對時更新dp值。由於合法的括號對都是巢狀或者並列的,所以第三層的列舉中間點只能幫我們解決括號的並列,但是不能解決括號的巢狀,所以我們還要自己加入判斷,即當該區間的左右端點括號匹配時,dp[l][r]=dp[l+1][r-1]+1
路徑回溯
這個也是典型,有兩種方法,一種是不開闢陣列,通過原來的dp轉移方程來遞迴,另一種是開一個數組(一般dp過程可以簡化陣列維度,但路徑回溯不可以,不過少部分題也可以),這個陣列用來記錄前驅(就是由誰更新了它),然後層層訪問前驅即可。
以前寫揹包的路徑回溯,兩種方法都比較簡單,現在看區間dp,感覺第二種好用點。區間dp由於第三層迴圈的存在,所以兩種方法都會麻煩一點,第一種得遍歷中間點,第二種得遞迴左區間和右區間。
程式碼:
#include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int N = 1e2+10 , M = N<<1,mod=1e9+7; typedef long long LL; typedef pair<int,int> PII; //#define x first //#define y second //int h[N],e[M],ne[M],idx; // //void add(int a,int b) //{ // e[idx]=b,ne[idx]=h[a],h[a]=idx++; //} struct Node { int l1,r1; int l2,r2; }; char s[N]; int f[N][N]; Node path[N][N]; int st[N]; void dfs(int l,int r) //路徑回溯 { Node t =path[l][r]; if(t.l1==l+1&&t.r1==r-1) { st[l]=st[r]=1; dfs(l+1,r-1); } else if((t.l1|t.l2|t.r1|t.r2)==0) return; //記得要加邊界條件 else { dfs(t.l1,t.r1); dfs(t.l2,t.r2); } } int check(int l,int r) //檢查括號是否匹配 { if(s[l]=='('&&s[r]==')'||s[l]=='['&&s[r]==']') return 1; return 0; } void deal(char c) //補全括號 { if(c=='('||c==')') cout<<"()"; else if(c=='['||c==']') cout<<"[]"; } void solve() //區間dp { cin>>s+1; int size=strlen(s+1); for(int len=2;len<=size;len++) for(int r=len;r<=size;r++) { int l=r-len+1; if(check(l,r)) //額外的判斷條件 { Node& t =path[l][r]; if(f[l][r]<f[l+1][r-1]+1) f[l][r]=f[l+1][r-1]+1,t.l1=l+1,t.r1=r-1; } for(int k=l;k<r;k++) { Node& t =path[l][r]; int sum=f[l][k]+f[k+1][r]; if(sum>f[l][r]) { f[l][r]=sum; t.l1=l,t.r1=k; t.l2=k+1,t.r2=r; } } } dfs(1,size); for(int i=1;i<=size;i++) { if(!st[i]) deal(s[i]); else cout<<s[i]; } cout<<'\n'; } int main() { ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); // int T; // cin>>T; // while(T--) solve(); }
鄉村郵局問題-Post Office(POJ-1160)