UVALive 3605 Roommate

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3069

题目大意:有两个人,他们在某一天各要依次用一些物品,每种物品只有一个,也就是相同的物品不能在同一个时间段用,每个人用每个物品都有一个时间,问你怎么安排,使他们都用完的时间最小,然后输出这个最小时间。

思路:很明显的DP,设两个为p、q, i、j 这两个维是很明显的,由于要记录时间差,所以还要增加一维表示p的时刻 - q的时刻,设d[ i ][ j ][ k ] ,表示 p 的前 i 个物品, q 的前 j 物品,p - q 的时刻差为k,这里还有一个限制,就是 k 这一部分只能是某个单件物品产生的(这个是纯属我看着别人AC代码的个人理解,。  = =),然后就是画图分类讨论了,由于比较烦,这里就不一一列举了,具体看代码吧。。

自己想的时候,3个状态倒是很容易想,然后我竟然转移的是d[ i - 1][ j - 1],因为当时就觉得应该两个一起讨论,SB了,这样只会 1、1,2、2这样下去。。 其实是i、j - 1 和 i - 1、j 。。。= =

看了一眼别人代码,忽然才发现的,可就是有一点不好处理,也就是我上面说的那个个人理解,我感觉状态定义为这样,可以解释得通。。 就先这样理解吧,如果有哪位神牛路过,希望能指点一二。

ZOJ也有一道这个题目,可是就是ZOJ能过,LA上WA了。。 不知道为什么。。难道ZOJ数据水了。。。 看了大家都做得是ZOJ,好吧,ZOJ过了就好了吧。。还有就算不是WA,应该也是TLE,因为LA上是3S,而ZOJ有10S,而我的要跑4S+,汗,所以上面给的也是ZOJ 题目的网址。。。想不出有什么可以优化的方法,还请各路神牛赐教。。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF = 0x0fffffff;

int d[303][303][202];

int t_p[303],t_q[303];

int p[303],q[303];

int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        int n;
        scanf("%d",&n);
        for(int i = 1;i<=n;i++)
            scanf("%d",&t_p[i]);
        for(int i = 1;i <= n;i ++)
            scanf("%d",&t_q[i]);
        int len_p,len_q;
        scanf("%d%d",&len_p,&len_q);
        p[0] = q[0] = 0;
        for(int i = 1;i <= len_p;i++)
            scanf("%d",&p[i]);
        for(int i = 1;i <= len_q;i ++)
            scanf("%d",&q[i]);
        int pos = 100;
        for(int i = 0;i <= len_p; i ++)
            for(int j = 0;j <= len_q; j++)
                for(int k = -100 ;k <= 100 ;k++)
                    d[i][j][k+pos] = INF;
        d[0][0][0 + pos] = 0;
        for(int i = 0;i <= len_p; i++)
            for(int j = 0;j <= len_q ;j++)
            {
                for(int k = -100;k<=100;k++)
                {
                    if(d[i][j][k + pos] >= INF) continue;
                    if(j < len_q && p[i] == q[j +1])
                    {
                        if(k >= 0)
                        {
                            d[i][j+1][-t_q[q[j+1]] + pos] = min(d[i][j][k + pos] + t_q[q[j+1]],d[i][j+1][-t_q[q[j+1]] + pos]);
                        }
                        else
                        {
                            d[i][j+1][-t_q[q[j+1]] + pos] = min(d[i][j][k + pos] + t_q[q[j+1]],d[i][j+1][-t_q[q[j+1]] + pos]);
                        }
                    }
                    else if(j < len_q)
                    {
                        if(k >= 0)
                            d[i][j+1][k - t_q[q[j+1]] + pos] = min(d[i][j][k + pos] + max(0,-k  + t_q[q[j+1]]),d[i][j+1][k - t_q[q[j+1]] + pos]);
                        else
                            d[i][j+1][-t_q[q[j+1]] + pos] = min(d[i][j][k + pos] + t_q[q[j+1]],d[i][j+1][-t_q[q[j+1]] + pos]);
                    }

                    if(i < len_p && p[i+1] == q[j])
                    {
                        if(k >= 0)
                            d[i+1][j][t_p[p[i+1]] + pos] = min(d[i][j][k + pos] + t_p[p[i+1]],d[i+1][j][t_p[p[i+1]] + pos]);
                        else
                            d[i+1][j][t_p[p[i+1]] + pos] = min(d[i][j][k +pos] + t_p[p[i+1]],d[i+1][j][t_p[p[i+1]] + pos]);
                    }
                    else if(i < len_p)
                    {
                        if(k >= 0)
                            d[i+1][j][t_p[p[i+1]] + pos] = min(d[i][j][k + pos] + t_p[p[i+1]],d[i+1][j][t_p[p[i+1]] + pos]);
                        else
                            d[i+1][j][k + t_p[p[i+1]] + pos] = min(d[i][j][k + pos] + max(0,k + t_p[p[i+1]]),d[i+1][j][k + t_p[p[i+1]] + pos]);
                    }
                }
            }

        /*for(int i = 0;i<=len_p;i++)
            for(int j = 0;j <= len_q ;j++)
                for(int k = -100;k<=100;k++)
                    if(d[i][j][k+pos] < INF)
                    {
                        printf("i = %d,j = %d,k = %d,d = %d\n",i,j,k,d[i][j][k+pos]);
                    }*/
        int ans =INF;
        for(int k = -100;k<=100;k++)
            ans = min(ans,d[len_p][len_q][k+pos]);
        printf("%d\n",ans);
    }
    return 0;
}

/*

3
2
1 2
2 1
2 2
1 2
1 2

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值