2012 ACM/ICPC Asia Regional Changchun Online 解题报告

hdu 4276 The Ghost Blows Light

这个题是树形dp比赛的时候一直超时,囧,最后将代码进行了优化,然后就过了

我的思路是,先将1到n的边先走,将走过的边时间改为0,然后其他的边都得走二次!剩下的就是简单的tree dp了,当时的代码太乱了!以至于超时!

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define N 110
#define M 510
int n,t;

struct note
{
    int v,next,time;
}edge[N*2];

int dat[N],head[N],kk;
void init()
{
    kk = 1;
    memset(head,-1,sizeof(head));
}
void add(int fa,int son,int val)
{
    edge[kk].time = val;
    edge[kk].v = son;
    edge[kk].next = head[fa];
    head[fa] = kk++;
}

int temp;

bool dfs(int rt,int fa)
{
    if(rt == n) return 1;
    for(int i = head[rt];i != -1;i = edge[i].next)
    {
        int son = edge[i].v;
        if(son == fa) continue;
        if( dfs(son,rt) )
        {
            temp += edge[i].time;
            edge[i].time = 0;
            return 1;
        }
    }
    return 0;
}
int dp[N][M];//表示第i个点消耗M时间时的耗费
int mma[N][M];
void dfs2(int rt,int fa)
{
    for(int i = head[rt];i != -1;i = edge[i].next)
    {
        int son = edge[i].v;
        if(son == fa) continue;
        dfs2(son,rt);
         int cost = edge[i].time*2;
        /**
        第二层循环的j从大到小循环是因为cost肯能是0
        这儿使用的是滚动数组计数,当cost=0时,dp[rt][i]就会使用本次的dp[rt][i];造成错误
        从大到小循环,可以解决的问题是,最开始使用的dp[rt][i]必是上一次的,
        且以后不会再用点dp[rt][i];
        */
        for(int i = t;i >= cost;i--)
            for(int j = i-cost;j >= 0;j--)//这个顺序怎么会有问题???  //for(int j = 0;j <= i-cost;j++)
                dp[rt][i] = max(dp[rt][i],dp[rt][j] + dp[son][i - cost - j]);
    }

    for(int i = 0;i <= t;i++)    dp[rt][i] += dat[rt];
}

int main()
{
    while(scanf("%d%d",&n,&t) != EOF)
    {
        init();
        int a,b,v;
        for(int i = 1;i < n;i++)
        {
            scanf("%d%d%d",&a,&b,&v);
            add(a,b,v);
            add(b,a,v);
        }
        for(int i = 1;i <= n;i++) scanf("%d",&dat[i]);

        memset(dp,0,sizeof(dp));

        temp = 0;
        dfs(1,-1);
        if(temp > t)
        {
            printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
            continue;
        }
        t-= temp;
        dfs2(1,-1);

        printf("%d\n",dp[1][t]);
    }
    return 0;
}
/*
2 1
1 2 1
1 1

5 10
1 2 2
2 3 2
2 5 3
3 4 3
1 2 3 4 5

5 10
1 2 2
2 3 2
2 5 8
3 4 3
1 2 3 4 5

5 10
1 2 3
2 3 2
2 5 8
3 4 3
1 2 3 4 5
*/

hdu 4277 USACO ORZ

这个题应该是离散化 dp 吧

重点工作是判重问题,我的方法是:将前i个数构成的三边中第一大的和第二大的作为判重的标准!

/**
1011
*/
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <utility>
using namespace std;

int dat[100];

int sum;
struct note
{
    int a,b,c;
}re[1000000];
bool cmp(const note a,const note b)
{
    return a.a < b.a || (a.a == b.a && a.b < b.b) || (a.a == b.a && a.b == b.b && a.c < b.c);
}
int kk;
void sort(int &a,int &b,int &c)
{
    if(a > b) swap(a,b);
    if(a > c) swap(a,c);
    if(b > c) swap(b,c);
}
bool check(int a,int b)
{

    int c = sum - a - b;
    if(a+b > c && b + c > a && a+c > b)
    {
        //cout << a << " " << b << " " << c << "\n";
        sort(a,b,c);
        re[kk].a = a;
        re[kk].b = b;
        re[kk].c = c;
        kk++;
        return 1;
    }
    return 0;
}
pair<int,int> _make_pair(int _sum,int a,int b)
{
    int c = _sum - a - b;
    sort(b,a,c);
    if(a > b) return make_pair(a,b);
    return make_pair(b,a);
}
bool same(note a,note b)
{
    return a.a == b.a && a.b == b.b && a.c == b.c;
}
int main()
{
    int sss = 1;
    for(int i = 0;i < 15;i++) sss *= 3;
    //cout << sss;
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        map < pair<int ,int > , int > dp[16];
        scanf("%d",&n);
        for(int i = 0;i < n;i++) scanf("%d",&dat[i]);
        sum = 0;
        for(int i = 0;i < n;i++) sum += dat[i];

        //pair pp(0,dat[0]);
        dp[0] [ make_pair(dat[0],0) ] ++;
        dp[0] [ make_pair(0,0) ] ++;
        int _sum = dat[0];
        for(int i = 1;i < n;i++)
        {
            _sum += dat[i];
            map<pair<int,int>,int>::iterator it = dp[i-1].begin();
            for(;it!=dp[i-1].end();++it)
            {
                pair <int,int> p = it->first;
                dp[i][_make_pair(_sum,p.first+dat[i],p.second)]++;
                dp[i][_make_pair(_sum,p.first,p.second+dat[i])]++;
                dp[i][_make_pair(_sum,p.first,p.second)]++;
            }
        }
        int ree = 0;
        kk = 0;
        map<pair<int,int>,int>::iterator it = dp[n-1].begin();
        for(;it!=dp[n-1].end();++it)
        {
            pair <int,int> p = it->first;
            check(p.first,p.second) ;
        }
        sort(re,re+kk,cmp);

        if(kk == 0) ree = 0;
        else
        {
            ree = 1;
            for(int i = 1;i < kk;i++)
            {
                if( !same(re[i],re[i-1]) ) ree++;
            }
        }
        cout << ree << "\n";
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值