1. 程式人生 > 其它 >sdutoj 動態規劃專題

sdutoj 動態規劃專題

Overview | SDUT OnlineJudge

動態規劃:

1.確定dp陣列的含義

2.找到遞推表示式

3.確定邊界值,左邊初始化,那一定左退右,上邊初始化,一定上推下

動態規劃是1生2,2生3的問題,後一個結果一定與前一個或前幾個結果有關係

A - 遞迴的函式

最簡單的形式,只是儲存了歷史記錄

 1 #include<iostream>
 2 using namespace std;
 3 int p[21][21][21]={0};
 4 int f(int a,int b,int c)
 5 {
 6     if(a<=0||b<=0||c<=0
) 7 return 1; 8 else if(a>20||b>20||c>20) 9 { 10 if(p[20][20][20]==0) 11 p[20][20][20]=f(20,20,20); 12 return p[20][20][20]; 13 } 14 else if(a<b&&b<c) 15 { 16 if(p[a][b][c]==0) 17 p[a][b][c]=f(a,b,c-1)+f(a,b-1,c-1)-f(a,b-1
,c); 18 return p[a][b][c]; 19 } 20 else 21 { 22 if(p[a][b][c]==0) 23 p[a][b][c]=f(a-1,b,c)+f(a-1,b-1,c)+f(a-1,b,c-1)-f(a-1,b-1,c-1); 24 return p[a][b][c]; 25 } 26 } 27 int main() 28 { 29 int a,b,c; 30 while(cin>>a>>b>>c)) 31 cout<<f(a,b,c)<<endl;
32 return 0; 33 }

B - 數字三角形問題(最簡單的動態規劃)

//動態規劃解決問題的思路:

//大化小,把原本的多種情況,每次遞減,最後彙總成只有一種情況

//動態規劃:1.一定涉及到記錄狀態

//用一個數組進行記錄

//         2.定義出記錄陣列的含義,比如這道題的含義是最大值

//         3.找到遞推關係式,可以把大問題看成兩步走的小問題,方便找關係

//         4.找起點並進行初始化,正方向和反方向都想一下 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main()
 4 {
 5     int n,a[101][101],dp[101][101];
 6     cin>>n;
 7     for(int i=1;i<=n;i++)
 8     {
 9         for(int j=1;j<=i;j++)
10         {
11             cin>>a[i][j];
12         }
13     }
14     for(int i=1;i<=n;i++)
15     dp[n][i]=a[n][i];
16     for(int i=n-1;i>=1;i--)
17     {
18         for(int j=1;j<=i;j++)
19         {
20             if(dp[i+1][j]>dp[i+1][j+1])
21             {
22                 dp[i][j]=dp[i+1][j]+a[i][j];
23             }
24             else
25             dp[i][j]=dp[i+1][j+1]+a[i][j];
26         }
27     }
28     cout<<dp[1][1]<<endl;
29     return 0;
30 }

C - 小鑫去爬山

//遞迴公式:未知的位置=已知的位置進行操作 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main()
 4 {
 5     int n;
 6     int a[101][101],dp[101][101];
 7     while(cin>>n)
 8     {
 9         fill(a[0],a[0]+101*101,0);
10         fill(dp[0],dp[0]+101*101,0);
11         for(int i=1;i<=n;i++)
12         {
13             for(int j=1;j<=i;j++)
14             {
15                 cin>>a[i][j];
16             }
17         }
18         for(int i=1;i<=n;i++)
19         dp[n][i]=a[n][i];
20         for(int i=n-1;i>=1;i--)
21         {
22             for(int j=1;j<=n;j++)
23             {
24                 dp[i][j]=min(dp[i+1][j],dp[i+1][j+1])+a[i][j];
25             }
26         }
27         cout<<dp[1][1]<<endl;
28     }
29  } 

D - 最長公共子序列問題

//初始化了第0行和第0列(左邊和上邊)

//只能用已經有的求沒有的,所以方向只能是左到右或者右到左

//ch1,ch2的下標0,實際上對應的是dp陣列的下標1i,jdp的下標,i-1,j-1才是ch1ch2的下標

//也是一個打表的過程,找出每一維的最大值,再更新下一個,有點像01揹包

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int dp[501][501];
 4 int f(string ch1,string ch2)
 5 {
 6     int n=ch1.size();
 7     int m=ch2.size();
 8     for(int i=0;i<=n;i++)
 9     {
10         dp[i][0]=0;
11     }
12     for(int i=0;i<=m;i++)
13     {
14         dp[0][i]=0;
15     }
16     for(int i=1;i<=n;i++)
17     {
18         for(int j=1;j<=m;j++)
19         {
20             if(ch1[i-1]==ch2[j-1])
21             {
22                 dp[i][j]=dp[i-1][j-1]+1;
23             }
24             else
25             dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
26         }
27     }
28     return dp[n][m];
29 }
30 int main()
31 {
32     string ch1,ch2;
33     cin>>ch1>>ch2;
34     cout<<f(ch1,ch2)<<endl;
35     return 0;
36 }

E - 最長上升子序列

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[1010];
 4 int dp[1010];
 5 int main()
 6 {
 7     int n;
 8     int mx=0;
 9     cin>>n;
10     for(int i=1;i<=n;i++)
11     {
12         cin>>a[i];
13     }
14     for(int i=1;i<=n;i++)
15     {
16         dp[i]=1;
17         for(int j=1;j<=i;j++)
18         {
19             if(a[i]>a[j])
20             dp[i]=max(dp[i],dp[j]+1);
21         }
22         mx=max(dp[i],mx);
23     }
24     cout<<mx<<endl;
25     return 0;
26 }

F - 上升子序列

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main()
 4 {
 5     int maxn=0;
 6     int n;
 7     int a[1010],dp[1010];
 8     cin>>n;
 9     for(int i=1;i<=n;i++)
10     {
11         cin>>a[i];
12     }
13     for(int i=1;i<=n;i++)
14     {
15         dp[i]=a[i];
16         for(int j=1;j<=i;j++)
17         {
18             if(a[i]>a[j])
19             {
20                 dp[i]=max(dp[i],dp[j]+a[i]);
21             }
22         }
23         maxn=max(dp[i],maxn);
24     }
25     cout<<maxn<<endl;
26     return 0;
27 }

H - 取數字問題

#include<bits/stdc++.h>
using namespace std;
int a[100][100];
int dp[100][100];
int main()
{
    int n,m;

    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            dp[i][j]=min(dp[i-1][j],dp[i][j-1])+a[i][j]; 
        }
    }
    if(dp[n][m]<=0)
    cout<<"-1"<<endl;
    else
    cout<<dp[n][m]<<endl;
    return 0;
}

I - 免費餡餅

//輸入兩個資料,大概率是二維

//後推前

//第一秒!=第零秒 ,注意邊界!!! 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[100001][12];
 4 int main()
 5 {
 6     ios::sync_with_stdio(false);
 7     cin.tie(0);
 8     cout.tie(0);
 9     int n;
10     int x,t;
11     while(cin>>n,n)
12     {
13         int rant=0;
14         fill(a[0],a[0]+100001*12,0);
15         for(int i=0;i<n;i++)
16         {
17             cin>>x>>t;
18             a[t][x]++;
19             if(rant<t)
20             {
21                 rant=t;
22             }
23         }
24         for(int i=rant-1;i>=0;i--)
25         {
26             for(int j=0;j<=10;j++)
27             {
28                 if(j==0)
29                 {
30                     a[i][j]+=max(a[i+1][j],a[i+1][j+1]);
31                 }
32                 else
33                 {
34                     a[i][j]+=max(max(a[i+1][j-1],a[i+1][j]),a[i+1][j+1]);
35                 }
36             }
37         }
38         cout<<a[0][5]<<endl;
39     }
40     return 0;
41  } 

J - 走迷宮(dfs)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,b1,b2,e1,e2;
 4 int dit[4][2]={0,-1,-1,0,0,1,1,0};
 5 int a[30][30],b[100];
 6 int book[30][30];
 7 int flag=0;
 8 int ii=1;
 9 void dfs(int b1,int b2,int ii)
10 {
11     if(b1==e1&&b2==e2)
12     {
13         flag=1;
14         for(int i=1;i<=ii-2;i+=2)
15         {
16             cout<<"("<<b[i]<<","<<b[i+1]<<")";
17             if(i!=ii-2)
18             cout<<"->";
19         }
20         cout<<endl;
21         return;
22     }
23     for(int i=0;i<4;i++)
24     {
25         int x=b1+dit[i][0];
26         int y=b2+dit[i][1];
27         if(a[x][y]==0||book[x][y]==1)
28         continue;
29         book[x][y]=1;
30         b[ii]=x;
31         b[ii+1]=y;
32         dfs(x,y,ii+2);
33         book[x][y]=0;
34     }
35 }
36 int main()
37 {
38     while(scanf("%d %d",&n,&m) == 2)
39     {
40         for(int i=1;i<=n;i++)
41     {
42         for(int j=1;j<=m;j++)
43         {
44             cin>>a[i][j];
45         }
46     }
47     cin>>b1>>b2>>e1>>e2;
48     book[b1][b2]=1;
49     b[1]=b1;
50     b[2]=b2;
51     ii+=2;
52     dfs(b1,b1,ii);
53     if(!flag)
54     cout<<"-1"<<endl;
55     }
56     
57     return 0;
58 }