標籤:style blog color io os for 資料 sp div
開一個dp[30010][3]的數組
其中dp[i][j]表示把第i個數改成j最少要花多少次
那麼狀態轉移方程就列出來了:
令a=1 j!=a[i]
0 j==a[i]
那麼dp[i][1]=dp[i-1][1]+a;
dp[i][2]=min(dp[i-1][1],dp[i-1][2])+a;
那麼根據空間最佳化原理,我們的第一維的i不過是為了遞推,那麼可以最佳化掉。
不過要注意的是,dp【2】的狀態要先求,否則測試資料會是3,因為沿用了本次的dp【1】,而非上次的dp【1】。
#include <iostream>#include <cstdio>#include <iostream>#include <cstdio>#include <memory.h>using namespace std;const int maxn=30002;//int dp[maxn][3];int dp[maxn];int cow[maxn];int main(){ // freopen("in.txt","r",stdin); int n; cin >> n; for(int i=1;i<=n;i++) { cin >> cow[i]; int flag; if(cow[i]==2) flag=0; else flag=1; //dp[i][2]=min(dp[i-1][1],dp[i-1][2])+flag; dp[2]=min(dp[1],dp[2])+flag; if(flag==0)flag=1; else flag=0; // dp[i][1]=dp[i-1][1]+flag; dp[1]=dp[1]+flag; } //cout << min(dp[n][1],dp[n][2])<< endl; cout << min(dp[1],dp[2])<< endl; return 0;}
左右遍曆,計算left【i】+right【i】的max:
#include <iostream>#include <cstdio>#include <iostream>#include <cstdio>#include <memory.h>using namespace std;#define maxn 30002int s[maxn],l[maxn],r[maxn];int main(){ //freopen("in.txt","r",stdin); memset(s,0,sizeof(s)); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); int n; cin >> n; for(int i=1;i<=n;++i) { cin >> s[i]; } if(s[1]==1) { l[1]=1; } for(int i=2;i<=n;i++) { if(s[i]==1) { l[i]=l[i-1]+1; } else l[i]=l[i-1]; } if(s[n]==2) { r[n]=1; } for(int i=n-1;i>=0;i--) { if(s[i]==2) { r[i]=r[i+1]+1; } else r[i]=r[i+1]; } int max=0; for(int i=1;i<=n;i++) { if(l[i]+r[i]>max) { max=l[i]+r[i]; } } cout << n-max << endl; return 0;}
還有一個不錯的方法,我們先計算1的個數,然後從前遍曆,每次判斷:是2就自加1,不是就自減1,其中儲存min,則為結果。實際上也為dp,每次的i值代表,編號為i的數組前面不可更改的數字1個數。
#include <iostream>#include <cstdio>using namespace std;const int MAX=30000+10;int a[MAX]; //儲存輸入的串int main(){ //freopen("in.txt","r",stdin); int cnt; //數組元素的個數 int i; int min; //最少要改變的次數 scanf("%d",&cnt); int num1=0; for (i=0;i<cnt;i++) { scanf("%d",&a[i]); if (a[i] == 1) num1++; } min=num1; for (i=0;i<cnt;i++) { (a[i] == 1) ? num1-- : num1++; if (min > num1) min = num1; } printf("%d\n",min); return 0;}
【經典dp】 poj 3671