• 【USACO2.3】解题报告


    前言

    本章主要是动态规划,但是其中几道题的方法比较多,我采用了其他的方法。
    题目已经开始变难,有几道题还特别值得思考。已经达到普及T3/T4T3/T4水平。
    USACO:http://train.usaco.org/


    2.3.1.Longest Prefix

    博客地址


    2.3.2.Cow Pedigrees

    思路:

    这道题还是很有难度的。
    很明显是一个DPDP,但是一开始一直在往(要递归的那种)树形DPDP那方面想,后来发现不行,于是就开始推方程。
    考虑到每种转移都是和第i1leq i-1层有关的,所以就想到设f[i][j]f[i][j]表示前ii个节点在前jj层的方案数。
    那么很明显,如果根节点左边有kk个节点,那么右边就有ik1i-k-1个节点,那么左右的方案数就相乘即可。
    那么方程就是
    f[i][j]=k=1ki&&(k&1)f[i][j]+f[k][j1]×f[ik1][j1]f[i][j]=sum^{kleq i&&(k&1)}_{k=1}f[i][j]+f[k][j-1] imes f[i-k-1][j-1]
    最终答案即为f[n][m]f[n][m1]f[n][m]-f[n][m-1]


    代码:

    /*
    ID:ssl_zyc2
    TASK:nocows
    LANG:C++
    */
    #include <cstdio>
    using namespace std;
    
    const int N=300;
    const int MOD=9901;
    int n,m,f[N][N];
    
    int main()
    {
    	freopen("nocows.in","r",stdin);
    	freopen("nocows.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;i++)
    		f[1][i]=1;
    	for (int i=2;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			for (int k=1;k<i;k++)
    				f[i][j]=(f[i][j]+f[k][j-1]*f[i-k-1][j-1])%MOD;
    	printf("%d
    ",((f[n][m]-f[n][m-1])%MOD+MOD)%MOD);
    	return 0;
    }
    

    2.3.3.Zero Sum

    思路:

    基础深搜题。每一个位置搜索放置空格,++-,然后checkcheck一下就可以了。

    代码:

    #include <cstdio>
    using namespace std;
    
    int a[10],n;
    
    bool check()
    {
        int s=0,k=0,p=1;  //分别表示总和,这一部分的值和符号
        for (int i=1;i<=n;i++)
            if (a[i])  //不是空格
            {
                if (p==1) s+=k;
                if (p==2) s-=k;
                p=a[i];  //记录符号
                k=i;
            }
            else k=k*10+i;  //加空格
        if (p==1) s+=k;
        if (p==2) s-=k;
        if (!s) return 1;  //符合
        return 0;
    }
    
    void print()
    {
        putchar('1');
        for (int i=2;i<=n;i++)
        {
            if (a[i]==0) putchar(' ');
            if (a[i]==1) putchar('+');
            if (a[i]==2) putchar('-');
            putchar(i+48);
        }
        printf("
    ");
    }
    
    void dfs(int x)
    {
        if (x>n)
        {
            if (check()) print();
            return;
        }
        for (int i=0;i<=2;i++)  //一定要按照空格,+再到-的顺序枚举,因为要求字典序
        {
            a[x]=i;
            dfs(x+1);
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        a[1]=1;  //第一位必须是+
        dfs(2);
        return 0;
    }
    

    2.3.4.Money Systems

    完全背包模板。
    QWQ

    代码:

    #include <cstdio>
    #define ll long long
    #define N 10100
    #define M 30
    using namespace std;
    
    ll f[N];
    int n,m,a[M];
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
         scanf("%d",&a[i]);
        f[0]=1;
        for (int i=1;i<=n;i++)
         for (int j=a[i];j<=m;j++)
          f[j]+=f[j-a[i]];
        printf("%lld
    ",f[m]);
        getchar();
        getchar();
        return 0;
    }
    

    2.3.5.Controlling Companies

    思路:

    这道题正解是深搜,但是暴力也是过的。
    看代码吧。。。

    代码:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int N=110;
    int m,n,x,y,z,K[N][N],sum[N],SUM;
    	//K[i][j]表示公司i占公司j的股份
    bool q[N][N],ap[N];
    
    struct answer
    {
        int x,y;
    }ans[N*N];
    
    struct node
    {
        int x,s;
    }p[N][N];
    
    bool cmp(answer x,answer y)
    {
        if (x.x<y.x) return 1;
        if (x.x>y.x) return 0;
        if (x.y<y.y) return 1;
        return 0;
    }
    
    int main()
    {
        scanf("%d",&m);
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            ap[x]=ap[y]=1;
            K[x][y]=z;
            p[x][++sum[x]].x=y;
            p[x][sum[x]].s=z;
        }
        for (int i=1;i<=100;i++)
            for (int l=1;l<=100;l++)
                for (int j=1;j<=100;j++)  //时间复杂度平摊后为n^3
                    if (ap[i]&&ap[j]&&i!=j&&(!q[i][j])&&K[i][j]>50)
           			{
           	   			q[i][j]=1;
           	   			ans[++SUM].x=i;
           	   			ans[SUM].y=j;
           	   			for (int k=1;k<=sum[j];k++)
           	    			K[i][p[j][k].x]+=p[j][k].s;
           	   			break;  //break使得复杂度平摊
           			}
        sort(ans+1,ans+1+SUM,cmp);
        for (int i=1;i<=SUM;i++)
         	printf("%d %d
    ",ans[i].x,ans[i].y);
        return 0;
    }
    
  • 相关阅读:
    7-6
    7-5
    7-3
    7-4
    ios中怎样在本类中调用drawRect方法
    ios中怎么样判断路径最后的后缀名称
    ios中怎么样转行大小写
    ios中怎么样自动剪切图片周围超出的部分
    ios中如何计算(页数,行数,等等的算法)
    IOS中 如何去除Tabview里面cell之间的下划线
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998446.html
Copyright © 2020-2023  润新知