HDU 4341 Gold miner (分组背包)

先把线按照距离原点的距离排序,然后用叉积把在同一条直线上的点放在一起,

把在同一条线上的点中的前i个点当成一个点就转化成了分组背包。

写if(kas++) putchar('\n') 居然PE了,PE选手

#include<bits/stdc++.h>
using namespace std;
int N,T;
const int maxn = 203;
const int MAXT = 40005;
struct Point
{
    int x,y,t,v;

}P[maxn];

bool vis[maxn];
vector<int> Line[maxn];
int Line_cnt;
#define PB push_back

int Dot(const Point &a,const Point& b) { return a.x*b.x+a.y*b.y; }
double Length(const Point &x) { return sqrt(Dot(x,x)); }
int Cross(Point &a,Point &b)
{
    return a.x*b.y-b.x*a.y;
}
bool operator < (const Point& a,const Point & b) { return Length(a)<Length(b); }


void init()
{
    memset(vis,0,sizeof(vis));
    for(int i = 0; i < N; i++){
        scanf("%d%d%d%d",&P[i].x,&P[i].y,&P[i].t,&P[i].v);
    }
    sort(P,P+N);
    Line_cnt = 0;
    for(int i = 0; i < N; i++)if(!vis[i]){
        Line[Line_cnt].clear();
        for(int j = i; j < N; j++)if(!vis[j]){
            if(Cross(P[i],P[j]) == 0){
                vis[j] = true;
                Line[Line_cnt].PB(j);
            }
        }
        Line_cnt++;
    }
}

int f[2][MAXT];

void dp()
{
    fill(f[0],f[0]+1+T,0);
    fill(f[1],f[1]+1+T,0);
    for(int i = 0; i < Line_cnt; i++){
        int pre = i&1,cur = pre^1;
        int totV = 0, totT = 0;
        for(int j = 0; j < Line[i].size(); j++){
            Point& x = P[Line[i][j]];
            totV += x.v; totT += x.t;
            for(int k = T; k >= totT; k--){
                f[cur][k] = max(f[cur][k],f[pre][k-totT]+totV);
            }
        }
        for(int k = 0; k <= T; k++){
            f[cur][k] = max(f[cur][k],f[pre][k]);
        }
    }
}

int main()
{
    int kas = 0;
    while(~scanf("%d%d",&N,&T)){
        init();
        dp();
        printf("Case %d: %d\n",++kas,max(f[0][T],f[1][T]));
    }
    return 0;
}

当时并不知道如何用一维数组实现,补上一维的伪代码

for 所有的组k

    for v=V..0 //从大到小枚举V

        for 所有的i属于组k 

            f[v]=max{f[v],f[v-c[i]]+w[i]}//从小的V转移,是上一组的状态

posted @ 2015-08-20 18:33  陈瑞宇  阅读(233)  评论(0编辑  收藏  举报