简单Dp----最长公共子序列,DAG最长路,简单区间DP等
/*
uva 111 * 题意: * 顺序有变化的最长公共子序列; * 模板; */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[100]; int mu[100]; int Dp[100][100]; int main() { int n,x; scanf("%d", &n); for(int i=1;i<=n;i++) { scanf("%d", &x); mu[x] = i; } while(scanf("%d", &x)!=EOF) { a[x] = 1; for(int i=2;i<=n;i++) { scanf("%d", &x); a[x] = i; } memset(Dp,0, sizeof(Dp) ); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(a[i] == mu[j]) Dp[i][j] = Dp[i-1][j-1] +1; else Dp[i][j] = max(Dp[i-1][j], Dp[i][j-1]); } } printf("%d\n",Dp[n][n]); } return 0; }
/* * uva103 * 题意: * DAG最长路; */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int cube[100][100]; int G[100][100]; int Dp[100]; int pre[100]; int n,di; void Dfs(int u) { for(int i=1;i<=n;i++) { if(i==u) continue; if( G[u][i]!= -1 ) { if(Dp[i] < Dp[u]+G[u][i]) { Dp[i] = Dp[u] + G[u][i]; pre[i] = u; Dfs(i); } } } } void print(int u) { if(pre[u]!=-1) print(pre[u]); if(pre[u]!= -1) printf(" "); printf("%d", u); } int main() { while(scanf("%d%d", &n,&di)!=EOF) { for(int i=1;i<=n;i++) for(int j=0; j<di; j++) scanf("%d", &cube[i][j]); memset(G, -1, sizeof(G)); memset(pre, -1, sizeof(pre)); for(int i=1;i<=n;i++) sort(cube[i],cube[i]+di); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j) continue; int flag =0 ; for(int x =0;x<di;x++) if( cube[i][x] >= cube[j][x]) { flag = 1; break; } if( !flag ) G[i][j] = 1; } for(int i=1;i<=n;i++) Dp[i] = 1; for(int i=1;i<=n;i++) Dfs(i); int ans =1; for(int i=2;i<=n;i++) { if(Dp[ans] < Dp[i]) ans =i; } printf("%d\n", Dp[ans]); print(ans); printf("\n"); } return 0; }
/* * uva10405 * 题意: * LCS; */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n1, n2; char s1[2005],s2[2005]; int Dp[2005][2005]; int LCS() { memset(Dp, 0, sizeof(Dp)); for(int i=1;i<=n1; i++) for(int j=1; j<=n2; j++) if( s1[i] == s2[j] ) Dp[i][j] = Dp[i-1][j-1] + 1; else Dp[i][j] = max(Dp[i-1][j], Dp[i][j-1]); return Dp[n1][n2]; } int main() { while(gets(s1+1)&& gets(s2+1)) { n1 = strlen(s1+1); n2 = strlen(s2+1); int ans = LCS(); printf("%d\n",ans); } return 0; }
/* * uva10003 * 区间Dp * 题意,给一个序列是要切开的位置,每次切一刀的代价是当前段的全长; * 最小代价; * 在区间开始和结尾加上0 和全长; * 枚举区间 长度、起点; * 这里的长度是跨越的要切的位置的个数,不是真正的长度; * 对于每一段内,枚举段内分割点,然后Dp出段内最小代价,直到全长; */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[55],len,n; int Dp[55][55]; int INF = 0x3f3f3f3f; int main() { while(scanf("%d", &len )!=EOF && len ) { memset(Dp, 0, sizeof(Dp)); scanf("%d", &n); for(int i=1;i<=n;i++) scanf("%d", &a[i]); a[0] = 0; a[n+1] = len; //区间Dp //Dp[i][j]表示左闭右开的区间i,j; for(int p = 1; p <= n+1 ; p++) for(int i = 0; i+p <= n+1 ; i++) { int j = i+p; int Min = INF; for(int k=i+1; k<j;k++) Min = min(Min, Dp[i][k]+Dp[k][j]+a[j]-a[i]); if( Min != INF ) Dp[i][j] = Min; } printf("The minimum cutting is %d.\n",Dp[0][n+1]); } return 0; }
/* * uva116 * 简单的Dp,前缀最小要倒着DP */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; int a[25][105]; int Dp[25][105]; int Next[25][105]; void print(int i,int j) { if(j<=1) return ; print(Next[i][j], j-1); if(j>2) printf(" "); printf("%d",Next[i][j]); } int main() { while(scanf("%d%d", &n, &m)!=EOF) { for(int i=1;i<=n;i++) for(int j = 1;j<=m;j++) scanf("%d", &a[i][j]); memset(Dp, 0x3f, sizeof(Dp)); for(int i=1;i<=n;i++) Dp[i][m] = a[i][m]; for(int i=m-1;i>0;i--) { for(int j=1;j<=n;j++) { int s[3]={j-1,j,j+1}; if(j-1==0) s[0] = n; if(j+1>n) s[2] = 1; sort(s,s+3); int t = s[0]; Dp[j][i] = Dp[t][i+1] + a[j][i]; Next[j][i] = t; t = s[1] ; if(Dp[j][i] > Dp[t][i+1] + a[j][i]) { Dp[j][i] = Dp[t][i+1] + a[j][i]; Next[j][i] = t; } t = s[2] ; if(Dp[j][i] > Dp[t][i+1]+a[j][i]) { Dp[j][i] = Dp[t][i+1] + a[j][i]; Next[j][i] = t; } } } int ans =1; for(int i=2;i<=n;i++) if(Dp[ans][1] > Dp[i][1]) ans = i; // print(ans,m); printf("%d",ans); int x =ans, y=1; while(y<m) { printf(" %d", Next[x][y]); x = Next[x][y]; y++; } printf("\n%d\n",Dp[ans][1]); } return 0; }
/* * uva562 * 给一列数,分成两堆,两堆的差最小; * 0-1背包处理出所有可能的和; * 然后从一半开始往下扫; */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[105]; int Dp[50005]; int main() { int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); for(int i=0;i<n;i++) scanf("%d", &a[i]); int sum = 0; for(int i=0;i<n;i++) sum += a[i]; memset(Dp, 0, sizeof(Dp)); Dp[0] = 1; for(int j=0; j<n;j++) for(int i= sum; i>=a[j]; i--) if(!Dp[i]) Dp[i] = Dp[i-a[j]]; for(int i=sum/2;i>=0;i--) if(Dp[i]) { printf("%d\n",sum-i-i); break; } } return 0; }
/************************************************************************* > File Name: uva348.cpp > Author: Baiyan > 题意:给一列矩阵的尺寸,问怎么样的计算顺序会使计算的次数最少 > > Created Time: 2016年04月19日 星期二 22时52分37秒 **********************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int INF = 0x3f3f3f3f; int a[15],b[15]; int Dp[20][20]; int vis[20][20]; void print(int l,int r) { if(r-l>0) { printf("("); print(l,vis[l][r]); printf(" x "); print(vis[l][r]+1,r); printf(")"); } else printf("A%d",l); } int main() { int n,k=1; while(scanf("%d", &n)!=EOF && n) { for(int i=1;i<=n;i++) scanf("%d%d", &a[i], &b[i]); memset(Dp, 0, sizeof(Dp)); memset(vis,0, sizeof(vis)); for(int p = 1;p<n;p++) { for(int i= 1;i+p<=n;i++) { int j = i+p; Dp[i][j] = INF; for(int k = i; k<j; k++) { if(k==j) Dp[k][j] = 0; if(i==k) Dp[i][k] = 0; if(Dp[i][j] >= Dp[i][k]+Dp[k+1][j]+a[i]*b[j]*b[k]) { vis[i][j] = k; Dp[i][j] = Dp[i][k] + Dp[k+1][j] + a[i]*b[j]*b[k]; } } } } printf("Case %d: ", k++); print(1,n); printf("\n"); } return 0; }