简单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;
}

 

posted on 2016-04-19 22:51  bai_yan  阅读(248)  评论(0编辑  收藏  举报

导航