櫥窗佈置(洛谷P1854)
https://www.luogu.com.cn/problem/P1854
問題實際就是給定F束花和V個花瓶,以及各束花放到不同花瓶中的美學值,要求你找出一種擺放的方案,使得在滿足編號小的花放進編號小的花瓶中的條件下,美學值達到最大。
將問題進行轉化,找出問題的原型。首先,看一下上述題目的樣例資料表格。
將擺放方案的要求用表格表現出來,則擺放方案需要滿足:每行選且只選一個數(花瓶);擺放方案的相鄰兩行中,下面一行的花瓶編號要大於上面一行的花瓶編號兩個條件。
這時可將問題轉化為:給定一個數字表格,要求程式設計計算從頂行至底行的一條路徑,使得這條路徑所經過的數字總和最大(要求每行選且僅選一個數字)。
同時,路徑中相鄰兩行的數字,必須保證下一行數字的列數大於上一行數字的列數。
看到經過轉化後的問題,發現問題與“數學三角形”問題十分相似,
因此也採用相似的寫法
標程程式碼
···cpp
include
include
include
using namespace std;
int main()
{
int a[101][101],b[101][101],c[101][101],d[101]; //a[i][j] 花束i放在花瓶j中的美學值
//b[i][j] 前i束花放在前j個花瓶中的最優解
//c[i][j] 在b[i][j]的最優解中,花束i-1的位置
int f,v,i,j,k,max; //f , v 花束和花瓶的數目
cin>>f>>v;
for (i=1;i<=f;i++)
for (j=1;j<=v;j++)
cin>>a[i][j];
memset(b,128,sizeof(b)); //這樣處理,可以保證每束花都放進花瓶
for (i=1;i<=v-f+1;i++) //初始化第1束花放在第i個花瓶的情況
b[1][i]=a[1][i];
for (i=2;i<=f;i++)
for (j=i;j<=v-f+i;j++)
for (k=i-1;k<=j-1;k++) //列舉花束i-1的位置
if (b[i-1][k]+a[i][j]>b[i][j])
{
b[i][j]=b[i-1][k]+a[i][j]; //更新當前最優解
c[i][j]=k; //前一個花束的位置為k
}
max=-2100000000;
for (i=f;i<=v;i++)
if (b[f][i]>max)
{
max=b[f][i]; //選擇全域性最優解
k=i; //k最後一束花的位置
}
cout<<max<<endl; //列印最優解
for (i=1;i<=f;i++)
{
d[i]=k;
k=c[f-i+1][k];
}
for (i=f;i>=2;i--)
cout<<d[i]<<" ";
cout<<d[1]<<endl;
}
我的寫法(區別是輸出路徑的方式一個是遞推一個是遞迴) ```cpp #include<algorithm> #include<cstring> #include<cstdio> using namespace std; const int maxn=1010; int f,v; int d[maxn][maxn]; int dp[maxn][maxn],pre[maxn][maxn]; void print(int x,int y) { if(pre[x][y]==y) { printf("%d ",y); return; } print(x-1,pre[x][y]); printf("%d ",y); } int main() { scanf("%d%d", &f, &v); for(int i=1;i<=f;i++) { for(int j=1;j<=v;j++) { scanf("%d", &d[i][j]); } } for(int i=1;i<=v-f;i++) { dp[1][i]=d[1][i]; pre[1][i]=i; } for(int i=2;i<=f;i++) { for(int j=i;j<=v-f+i;j++) { for(int k=1;k<j;k++) { if(dp[i-1][k]+d[i][j]>dp[i][j]) { dp[i][j]=dp[i-1][k]+d[i][j]; pre[i][j]=k; } } } } int tx=f,ty,ans=0; for(int i=f;i<=v;i++) { if(dp[f][i]>ans) { ans=dp[f][i]; ty=i; } } printf("%d\n",ans); print(tx,ty); return 0; }