JOJ水DP匯總

來源:互聯網
上載者:User

 花點時間整理下以前A掉的水題 , 鞏固下基礎 ,也希望能再細節處理上有所提高

可以用動態規劃來解決的問題 要滿足無後效性(DAG)、最優子結構

 

【無特殊說明都是JOJ的題】

/***********************************************************************************/

2526: medic採藥問題, 經典01背包,不必裝滿

1維空間,用組合數學的產生函數思想更好理解一些

#include <cstdio>#include <string.h>const int maxn=102;int w[maxn],v[maxn],ans[1005];int main (){    int t,m,i,j;    while (scanf("%d%d",&t,&m)==2)    {        for (i=0 ; i<m ; ++i)         scanf("%d%d",w+i,v+i);        memset (ans,0,sizeof(ans));        for (i=0 ; i<m ; i++)//0...N         for (j=t ; j>=w[i] ; --j)//V...cost         {                ans[j]>?=ans[j-w[i]]+v[i];         }         //for (i=0 ; i<=t ; i++)          printf("%d\n",ans[t]);    }    return 0;}

/***********************************************************************************/

1424 1583 2201 1176 可看作品質為1的,完全背包計數問題,注意初始化,理解成產生函數更好些

#include<stdio.h> #include<memory.h> using namespace std;const int maxn=7500;int c[5]={1,5,10,25,50}; int v; int f[maxn];  int main() {     memset(f,0,sizeof(f));     f[0]=1;     for(int i=0;i<5;i++)     for(int j=c[i];j<=maxn;j++)     {         f[j]+=f[j-c[i]];//重要     }     while(scanf("%d",&v)==1)     {         printf("%d\n",f[v]);     }      return 0; } 

/***********************************************************************************/

 

POJ 2392 多重背包 模板

#include <cstdio>#include <cstring>#include <algorithm>#define max(a,b) (a>b?a:b)using namespace std;const int maxn=500;int dp[5][40050];struct Item {    int h,a,c;}blo[maxn];bool cmp(const Item & a , const Item & b){    return a.a<b.a;}void O1Pack(int f[] , int c , int w , int V){    for (int v=V ; v>=c ; --v)        f[v]=max(f[v-c]+w , f[v]);}void ComPack(int f[] , int c , int w , int V){    for (int v=c ; v<=V ; ++v)        f[v]=max(f[v-c]+w , f[v]);}void MulPack(int f[] , int c , int w , int m , int V){    if(c*m>=V)    {        ComPack(f , c , w , V);        return ;    }    int k=1;    while (k<m)    {        O1Pack(f , k*c , k*w , V);        m-=k;        k*=2;    }    O1Pack(f , c*m , w*m , V);}int main (){    int c,w,m;    while (~scanf("%d",&m))    {        memset (dp , 0 , sizeof(dp));        for (int i=0 ; i<m ; ++i)        {            scanf("%d%d%d",&blo[i].h , &blo[i].a , &blo[i].c);        }        sort(blo , blo+m , cmp);        for (int i=0 ; i<m ; ++i)        {            MulPack(dp[0] , blo[i].h , blo[i].h , blo[i].c , blo[i].a);        }        int ans=0;        for (int i=0 ; i<=blo[m-1].a ; ++i)        ans=max(dp[0][i],ans);        printf("%d\n",ans);    }    return 0;}

/***********************************************************************************/

HDU 1561泛化背包

/**O(n*V)泛化背包 演算法來自論文【淺談幾類背包題】4686406 2011-10-01 14:23:10 Accepted 1561 0MS 372K 1776 B G++ Geners **/#include <cstdio>#include <cstring>#define max(a,b) (a>b?a:b)const int maxn=205;struct Edge {    int v,next;}edge[maxn];int head[maxn],cnt;void addedge(int u,int v){    edge[cnt].v=v;    edge[cnt].next=head[u];    head[u]=cnt++;}int w[maxn],dp[maxn][maxn],node;int n,m;void dfs(int u , int c){    for (int p=head[u] ; ~p ; p=edge[p].next)    {        int &v=edge[p].v;        for (int j=0 ; j<c ; ++j)            dp[v][j]=dp[u][j]+w[v];///取兒子的時候,父親必須取,因此直接將父親放入兒子,        dfs(v , c-1);///更新兒子        for (int j=1 ; j<=c ; ++j)///求2個有交集的泛化物品的並            dp[u][j]=max(dp[u][j] , dp[v][j-1]);///更新兒子後,再賦值給父親    }///對於樹的葉結點 我們可以把他處理成01Pack}int main (){    while (scanf("%d%d",&n,&m),(n||m))    {        memset(head , -1 , sizeof(head));        cnt=0;        for (int i=1 ; i<=n ; ++i)        {            scanf("%d %d" , &node , w+i);            addedge(node , i);        }        w[0]=0;        memset(dp , 0 , sizeof(dp));        dfs(0 , m);        printf("%d\n",dp[0][m]);    }    return 0;}

 

 

/***********************************************************************************/

 

 

2529 合唱 最長單調序列變形

用OPT1存上升的,OPT2存下降的,則第I個人的最大為OPT1[I]+OPT[I] -1  時間n^2 空間n

因為每個數都包含自己本身,所以初始化全為1。

/***********************************************************************************/

2511 經典數塔問題,從下往上搜

opt[i][j]=num[i][j];

for i m..0

for j i..0

opt[i][j]+=opt[i+1][j]>?opt[i+1][j+1];

 

/***********************************************************************************/

1826 三角剖分  有公式的 可以推

f[2]=1;f[3]=1;
f[i]=4*f[i-1]-6*f[i-1]/(i-1);

/***********************************************************************************/

1968 最長公用子序列 時間 n^2 空間n^2

階段不是很明顯,opt[i][j]表示從起點開始 str1長度為i,str2長度為j的最長公用子序列

#include <stdio.h>#include <memory.h>#include <string.h>const int maxn=200;char str1[maxn],str2[maxn];int opt[maxn][maxn];int same(int i,int j){    if(str1[i]==str2[j])     return 1;    return 0;}int main (){    int i,j;    while (scanf("%s%s",str1,str2)!=EOF)    {        memset (opt,0,sizeof(opt));        opt[1][1]=same(0,0);        int len1=strlen(str1);        int len2=strlen(str2);        int ans=0;        for (i=1 ; i<=len1 ; i++)         for (j=1 ; j<=len2 ; j++)         {             opt[i][j]=opt[i][j-1];             if(opt[i][j]<opt[i-1][j])opt[i][j]=opt[i-1][j];              if(opt[i][j]<(opt[i-1][j-1]+same(i-1,j-1)))               opt[i][j]=(opt[i-1][j-1]+same(i-1,j-1));         }        printf("%d\n",opt[len1][len2]);    }    return 0;}

 

/***********************************************************************************/

 1995 最大子段和 時間n

用sum寄存 首碼和,當sum<0時,清零,同時要記錄掃描過程sum的最大值 以及數值的最大值,因為有可能有全是負數的情況,但這時sum的最大值預設為0

2058 一樣的 多了些條件  記錄區間什麼的

/***********************************************************************************/

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.