/*
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;
}