幾道黑書上的簡單DP題

2021-06-08 23:52:35 字數 3638 閱讀 6287

這幾道經典的題本不應再由本菜囉嗦,無奈手癢總想貼點**~

poj1141 括號的匹配

dp[i][j]表示從i到j使括號匹配完整的最少需要新增的括號,有

dp[i][i]=1;

dp[i][j]=min(dp[i][k],[k+1][j]);

當s[i]=='(',s[j]==')'或者s[i]=='[',s[j]==']'時,dp[i][j]=min(dp[i][j],dp[i+1][j-1]);

記錄每個dp[i][i]新增的部分是什麼,添的位置在前還是在後,在dp的過程中,記錄dp的路徑,dp後沿路徑得解;

#include #include #include using namespace std;

const int nn=250;

int n,dp[nn][nn],r[nn][nn];

char s[nn],ad[nn];

void dfs(int i,int j)

if (r[i][j]==0)

else

}int main()

if (s[i]=='[')

if (s[i]==')')

if (s[i]==']')

}for (l=1; l

poj2288 狀態壓縮入門,不解釋不代表此題不經典不好,就是太經典的狀態壓縮了

#include #include #include using namespace std;

typedef long long ll;

int n,m;

ll dp[2][1<<12];

inline bool ok(int x,int y)

else return false;}}

return true;

}int main()

lim=(1<

#include #include #include using namespace std;

const int nn=110;

int n,bn,flag,mp[nn][nn],color[nn],belong[nn],cnt[nn][2];

int ans[nn][nn],id[nn][nn],dp[nn][nn];

void dfs(int u,int c)

}}void get_ans(int i,int k)

int main()

for (i=1; i<=n; i++)

for (j=1; j<=n; j++) if (mp[i][j])

mp[j][i]=1;

bn=0; flag=1;

memset(color,-1,sizeof(color));

memset(cnt,0,sizeof(cnt));

for (i=1; i<=n && flag; i++) if (color[i]==-1) bn++,dfs(i,0);

if (!flag)

memset(dp,0,sizeof(dp));

dp[0][0]=1;

for (i=1; i<=bn; i++)

for (j=0; j<=1; j++)

}for (k=(n+1)/2; k; k--) if (dp[bn][k]) break;

get_ans(bn,k);

printf("%d",k);

for (i=1; i<=n; i++) if (ans[belong[i]][color[i]]) printf(" %d",i);

printf("\n%d",n-k);

for (i=1; i<=n; i++) if (!ans[belong[i]][color[i]]) printf(" %d",i);

printf("\n");

return 0;

}

poj1848 樹形dp

#include #include #include #include using namespace std;

const int nn=110;

const int inf=16843009;

int n,ans=0,flag=0;

int dp[nn][3];

bool vis[nn]=;

vectoradj[nn];

void dfs(int u)

zoj1234 簡單線性dp(滾動陣列)

將原始資料的筷子長按從長到短存後,

記dp[i][j][0](i>=3*j)為前i個筷子分為j組的最小badness和,不使用第i個筷子;dp[i][j][1](i>=3*j)為前i個筷子分為j組的最小badness和,使用第i個筷子。

有 dp[i][j][0]=min; dp[i][j][1]=min+(a[i-1]-a[i])^2;

#include #include #include using namespace std;

int a[5005],dp[3][1002][2];

int main()

}printf("%d\n",min(dp[c][m][0],dp[c][m][1]));

}return 0;

}

poj1947 樹形dp+揹包

#include #include #include #include using namespace std;

const int nn=160;

vectoradj[nn];

bool vis[nn]=;

bool mark[nn][nn]=;

int n,p,dp[nn][nn];

void dfs(int u)

}}int main()

,最好的做法是先取中間的1,再取4個2,最後一起取兩邊的2個1。最後一步所取的2個1在原序列中的中間還有乙個1,也就是這兩個1不連續。序列更複雜時,最優解中某一步所取的字串來自的位置更是各種情況都有,二維的狀態(dp[i][j]表示新序列i到j取完所得價值)資訊太少,轉移時要就所取字串的位置來列舉所有的可能的組合,很是複雜。估計很多人思維和我一樣。雖然也想了要加維,又不好從何入手。

#include #include #include #include #include using namespace std;

typedef pairpii;

const int n = 210;

int n, a[n], c[n], last[n], prev[n], dp[n][n][n];

void init()

n = k;

memset(last, -1, sizeof(last));

for (int i = 0; i < n; i++)

memset(dp, -1, sizeof(dp));

}int dp(int i, int j, int k)

return dp[i][j][k] = ret;

}int main()

return 0;

}

待續。。。

黑書上的DP 30題

page section notitle submit 1131.5.1 例題1括號序列 poj1141 1161.5.1 例題2棋盤分割 poj1191 1171.5.1 例題3決鬥 sicily1822 1171.5.1 例題4 舞蹈家 懷特先生 acm icpc live archive 11...

poj 幾道簡單的dp題

題意 求使數列程先遞增後遞減的形式需要去掉的數字個數。當然也可以直接遞減或者只遞減不遞增。分析 用最長遞增子串行的方法求,然後列舉兩個起點的位置即可。include include include using namespace std const int inf 1e8 const int n 1...

狀壓dp幾道題

感覺現在只會用比較無腦比較暴力的狀壓dp,完全沒思考,就是列舉所有的狀態,等集訓結束了搜點要努力想dp方程的題做做。hdu3681 prison break 大體意思就是給了張地圖,走路要耗費能量,有能量池能補充能量,求要走完特定的幾個點初始能量的最小值 因為給的點很少所以可以用狀壓dp,走過的各自...