校赛题之( SDUT 2857 艺术联合会 && SDUT 2860 生日Party )

校赛过去之后,非常失望,但也看清了自己的短板,对题把握不到位,对递推类题目实在没辙。

这两个题本来没有打算再做,当校赛过去后,SJ给我讲了一下,明白比赛的时候找错方向了,也知道怎么做了,就没再敲。

这几天问的人挺多,决定自己也好好整理一下。

 

艺术联合会

题目链接:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2857

艺术联合会是个小DP + 贪心,只要找到转移方程,剩下就是敲代码的事。

这个题有这样的标准数据

其实可以发现,完成第n幅画需要先完成第n - 1幅画,那么,我们需要递推一下

这也就是说我们可以先求出这样的矩阵

 

红字部分是第一名画家完成每一幅画的时间,因为当他完成的第n幅画,第二个等等画家才能上手

绿底部分是第一幅画每个画家完成的时间,只有第一幅画完成,才有可能完成第二幅画

也就是说,决定第n幅画完成的制约条件是每个画家都花完并且前一幅画画完

那么在时间上将,第n幅画画完成的时间取决于前一幅画完成时间以及前一个画家完成这幅画的时间的最大值

因为即使有某个画家在某个环节画的快,他画完了只能先等着,所以时间计入取最大值。

 

那么根据上图矩阵,关系就出来了,f[i][k] = max (f[i][k - 1],f[i - 1][k]);

代码如下:

#include <stdio.h>
#include <stdlib.h>
#define qmax(a,b) a > b ? a : b

int tim[100000][10];

int main()
{
    int N;
    scanf ("%d",&N);

    while (N--)
    {
        int m,n;
        int i,k;
        scanf ("%d%d",&m,&n);

        for (i = 0;i < m;i++)
            for (k = 0;k < n;k++)
                scanf ("%d",&tim[i][k]);

        for (i = 1;i < n;i++)
            tim[0][i] += tim[0][i - 1];

        for (i = 1;i < m;i++)
            tim[i][0] += tim[i - 1][0];

        for (i = 1;i < m;i++)
        {
            for (k = 1;k < n;k++)
            {
                tim[i][k] += qmax(tim[i - 1][k],tim[i][k - 1]);
            }
        }

        for (i = 0;i < m;i++)
        {
            printf ("%d",tim[i][n - 1]);

            if (i < m - 1)
                printf (" ");
            else
                printf ("\n");
        }
    }
    return 0;
}


 

生日Party

题目链接:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2860

生日Party这个题比赛的时候看输入输出好多,就没细看= =

然后比赛完看到飞飞blog发这个题并注明BFS,我又读了一遍题发现就15个人,枚举就可以,BFS什么的应该很简单。

前几天WJW说自己枚举过不了,现在别人A的都是用的BFS

因为BFS就是枚举,所以枚举不可能过不了,于是就自己手敲了一下枚举遍历。

想起来当时在去威海的火车上好好复习了一下位操作,而且这次标记就15个人,决定不用标记数组,就用位处理做。

好在int是32位,标志15个人,远远富裕。

这次发现用位操作不仅方便枚举,用掩码还方便筛查,挺棒的。

 

代码如下:

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

int db[15] = {0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,
              0x00000020,0x00000040,0x00000080,0x00000100,0x00000200,
              0x00000400,0x00000800,0x00001000,0x00002000,0x00004000};
int ha[16];

int eha[20][20];
int main()
{
    int N;
    int i,k;

    scanf ("%d",&N);

    while (N--)
    {
        int n;
        scanf ("%d",&n);

        for (i = 0;i < n;i++)
            scanf ("%d",&ha[i]);

        for (i = 0;i < n;i++)
            for (k = 0;k < n;k++)
                scanf ("%d",&eha[i][k]);

        int tim = 1;

        for (i = 0;i < n;i++)
            tim *= 2;

        int enu = 0;
        int imax = 0;
        int ans;
        for (i = 0;i < tim;i++,enu++)
        {
            ans = 0;
            for (k = 0;k < n;k++)
                if ((enu & db[k]) == db[k])
                {
                    ans += ha[k];
                    for (int j = k + 1;j < n;j++)
                        if ((enu & db[j]) == db[j])
                            ans += eha[k][j];
                }

            imax = imax > ans ? imax : ans;
        }

        printf ("%d\n",imax);
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值