ZCMU - 2165: 黄金矿工

题目链接:点击打开链接


题目大意:略。


解题思路:DFS --> TLE;难点在于如何把直线问题转换成01背包问题:在相同角度基础上并且到原点距离短的优先在前排序后:
AC-1:先把相等角度的情况下,后者加上前者的 t 和 v,把它看成一个整体的状态来思考,最后通过 mk[i] 来控制跳跃到上一个不相等的元素。
AC-2:将在后面的元素的时间加上相邻前面元素(在一条直线上)的时间,可以理解成离散状态,该点需要的时间是ti+=t(i-1),但是这里需要另外声明临时变量,不可以用数组来加否则会影响dp结果


TLE 代码

#include<bits/stdc++.h>
#include<cmath>

#define mem(a,b) memset(a,b,sizeof a);

using namespace std;

typedef long long ll;

struct node
{
    double a;
    int t,v,s;
};

node nds[300];
int vis[300];
int n,m,x,y,rs,ans,pre;

int cmp(node n1,node n2)
{
    if(n1.a==n2.a)
        return n1.s<n2.s;
    return n1.a<n2.a;
}

void init()
{
    ans=rs=0;
    mem(vis,0);
    nds[0].a=0;
}

void dfs(int k)
{
    if(k>m)
    {
        rs=max(rs,ans-pre);
        return;
    }

    for(int i=1;i<=n;i++)
    {
        if(vis[i]==0 && (nds[i-1].a==nds[i].a&&vis[i-1]==1 || nds[i-1].a!=nds[i].a))
        {
            vis[i]=1;
            ans+=nds[i].v;
            pre=nds[i].v;
            dfs(k+nds[i].t);
            ans-=nds[i].v;
            vis[i]=0;
        }

    }
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&x,&y,&nds[i].t,&nds[i].v);
            nds[i].a=y*1.0/x;
            nds[i].s=y*y+x*x;
        }

        sort(nds+1,nds+1+n,cmp);

        dfs(0);

        printf("%d\n",rs);
    }

    return 0;
}


AC-1 代码

#include<bits/stdc++.h>

#define mem(a,b) memset(a,b,sizeof a)

using namespace std;

typedef long long ll;

struct node
{
    double a;
    int t,v,s;
};

node nds[300];
int n,m,x,y;
int dp[300][40000+100];

int cmp(node n1,node n2)
{
    if(n1.a==n2.a)
        return n1.s<n2.s;
    return n1.a<n2.a;
}

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        mem(dp,0);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&x,&y,&nds[i].t,&nds[i].v);
            nds[i].a=y*1.0/x;
            nds[i].s=y*y+x*x;
        }

        sort(nds+1,nds+1+n,cmp);

        int idx=1,mk[300];
        mk[1]=1; // 与 nds[i] 同步
        for(int i=2;i<=n;i++)
            if(nds[i].a!=nds[i-1].a)
                mk[i]=++idx;
            else
                mk[i]=idx;

        for(int i=1;i<=n;i++)
        {
            if(nds[i].a==nds[i-1].a)
            {
                nds[i].t+=nds[i-1].t, nds[i].v+=nds[i-1].v;
                for(int j=m;j>=0;j--)
                {
                    if(j>=nds[i].t)
                        dp[i][j]=max(dp[i-1][j],dp[mk[i]-1][j-nds[i].t]+nds[i].v); // mk[i]-1 可以打印dp看看分析下,因为要跳过前一个相同的,因为已经把前一个的t和v加上去了,表示把多个看为一个整体
                    else
                        dp[i][j]=dp[i-1][j];
                }

            }
            else
                for(int j=m;j>=0;j--)
                {
                    if(j>=nds[i].t)
                        dp[i][j]=max(dp[i-1][j],dp[i-1][j-nds[i].t]+nds[i].v);
                    else
                        dp[i][j]=dp[i-1][j];
                }


        }

//        for(int i=0;i<=n;i++)
//        {
//            for(int j=0;j<=m;j++)
//            {
//                printf("%d ",dp[i][j]);
//            }
//            puts("");
//        }

        printf("%d\n",dp[n][m]);
    }

    return 0;
}


AC-2 代码:

#include<bits/stdc++.h>
#include<cmath>

#define mem(a,b) memset(a,b,sizeof a)

using namespace std;

typedef long long ll;

struct node
{
    double a;
    int t,v,s;
};

node nds[300];
int n,m,x,y;
int dp[40000+100];

int cmp(node n1,node n2)
{
    if(n1.a==n2.a)
        return n1.s<n2.s;
    return n1.a<n2.a;
}

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        mem(dp,0);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d%d%d",&x,&y,&nds[i].t,&nds[i].v);
            nds[i].a=y*1.0/x;
            nds[i].s=hypot(x,y);
//            nds[i].s=y*y+x*x;
        }

        sort(nds,nds+n,cmp);

        int t=0;
        for(int i=0;i<n;i++)
        {
//            if(nds[i].a==nds[i-1].a) // 因为会影响到下面计算 j-nds[i].t 的结果,功能上是与下面?:代码一样的
//                nds[i].t+=nds[i-1].t;

            nds[i].a==nds[i-1].a?t+=nds[i].t:t=nds[i].t;

            for(int j=m;j>=t;j--)
                dp[j]=max(dp[j],dp[j-nds[i].t]+nds[i].v);
        }

        printf("%d\n",dp[m]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/dream_weave/article/details/80646589