21/7/2012 ICPC培训 第六天

算法练习心得
博主分享了四道算法题的解题过程及心得,包括01背包变形题、利用二分查找优化搜索题、解方程题及一道动态规划题。面对难题,博主表示要加强对抽象思维的训练。

今天本来安排刷DP的,可是各种不懂呀!!!勉强刷出两道题!

眼看没做出题,还是刷两道二分查找吧。

其他的就是讲解了昨天下午的比赛题目。各种思路,搞得我甚是膜拜。每种思路都很简洁,

把需要解决的问题抽象的很好很好。为啥我就不能想出来呢???无语吆。。。

不过膜拜归膜拜,有了思路得在这两天把没做出来的几题刷了。

最后,晚上,张浩然同学给我们简单介绍了下STL。

 

还是来讲讲我做的题吧。

第一题(HDU1881)

这题是01背包的变形。思路和01背包很像。

我搞不明白为什么要先对各个bg按照离校时间由小到大排序,然后再用01背包的方法解决?

期待,看到博文的大神赐教哇。。。

代码:

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

const int MAX=31;

int dp[MAX*MAX*2];
int maxTime,n;

struct node
{
    int h,l,t;
    bool operator < (const node &tmp) const
    {
        return t<tmp.t;
    } 
}temp[MAX];


//bool cmp(node a,node b)
//{
//    return a.t<b.t;
//}

void input()
{
    maxTime=0;
    
    for(int i=0;i<n;i++)
    {
        cin>>temp[i].h>>temp[i].l>>temp[i].t;
        
        maxTime=maxTime>temp[i].t?maxTime:temp[i].t;
    }
}

void pack()
{
    memset(dp,0,sizeof(dp));
    
    for(int i=0;i<n;i++)
    {
        for(int j=maxTime;j>=temp[i].l;j--)
        {
            if(temp[i].t>=j && dp[j]<dp[j-temp[i].l]+temp[i].h)
            {
                dp[j]=dp[j-temp[i].l]+temp[i].h;
            }
        }
    }
    
    int result=-1;
    for(int k=0;k<=maxTime;k++)
    {
        result=result>dp[k]?result:dp[k];
    }
    
    cout<<result<<endl;     
}
  
int main()
{
    while(cin>>n,n>=0)
    {
        input();
        
        //sort(temp,temp+n,cmp);
        sort(temp,temp+n); 
        
        pack();
    }
    
    return 0;
}


 

第二题(HDU2141)

看到这类题,爆搜很通用,前提是数据量不太大。这题显然爆搜超时。

如何优化呢?可以对C二分,也可以对A+B二分。对A+B二分时间性能更好点。

代码:

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

const int MAX=500;

int a,b,c,quary,ans,cas=1;
int A[MAX],B[MAX],C[MAX],D[MAX*MAX];
bool flag; 

void input()
{
    int i;
     
    for(i=0;i<a;i++)
    {
        scanf("%d",&A[i]);
    } 
    for(i=0;i<b;i++)
    {
        scanf("%d",&B[i]);
    }
    for(i=0;i<c;i++)
    {
        scanf("%d",&C[i]);
    }
}

void preDeal()
{
    int k=0;
     
    for(int i=0;i<a;i++)
    {
        for(int j=0;j<b;j++)
        {
            D[k++]=A[i]+B[j];
        }
    }
    
    sort(D,D+k); 
}

void binSearch(int low,int high)
{
    int mid=(low+high)/2;
    
    if(low+1==high && D[mid]!=ans) return;
     
    if(D[mid]==ans)
    {
        flag=true;
        return;
    }
    else if(D[mid]<ans)
    {
        binSearch(mid,high);
    }
    else
    {
        binSearch(low,mid);
    }
}
 
void deal()
{
    scanf("%d",&quary);
    printf("Case %d:\n",cas++);
     
    int temp,i,j;
    
    for(i=0;i<quary;i++)
    {
        scanf("%d",&temp);
        
        flag=false; 
        for(j=0;j<c;j++)
        {
            if(flag) break;
             
            ans=temp-C[j];
            
            binSearch(0,a*b-1);
        }
        
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
}       
         
int main()
{
    while(cin>>a>>b>>c)
    {
        input();
        
        preDeal();
        
        deal();
    }
    
    return 0;
} 


 

第三题(HDU2199)

这题是解方程。

这个方程在0—100范围内明显是递增的。所以,输入的y太大或太小就可以直接判断是No soulution!了。

另外,这题不能1Y的原因在于你选择的精度大小。刚开始我用的精度是1e-7,结果就TLE了。然后改成

1e-5,0MS过了。

代码:

#include<iostream>
#include<iomanip> 
#include<cmath>
using namespace std;

const double accurate=1e-5;  //这里精度写成1e-7,TLE了 

double x,y;
 
double calculate(double x)
{
    return 8*pow(x,4) + 7*pow(x,3) + 2*pow(x,2) + 3*x + 6 ;
}

void binSearch(double low,double high)
{
    double mid=(low+high)*1.0/2.0;
    
    if(fabs(calculate(mid)-y)<=accurate)
    {
        x=mid; 
        return;
    }
    else if(calculate(mid)<y)
    {
        binSearch(mid,high);
    }
    else
    {
        binSearch(low,mid);
    }
}     
     
int main()
{
    int cas;
    
    scanf("%d",&cas);
     
    while(cas--)
    {
        scanf("%lf",&y); 
        
        if(y<6 || y>807020306)
        {
            printf("No solution!\n");
            continue;
        }
        
        binSearch(0,100);
        
        cout<<setiosflags(ios::fixed)<<setprecision(4)<<x<<endl;
    }
    
    return 0;
} 

 

最后一题是昨天下午比赛的一道DP题,在同学的帮助下找到状态转移方程了!

然后晚上出题的同学又讲了一种完全不同构造方程的思路。可见的是DP借助数组来表达状态,

你给数组赋予不同的含义也就可以找到不同大方程。

DP很抽象,得加强练习了。。。

 

 

 

 

 

 

 

 

### 关于2024 ICPC网络预选赛的信息 #### 参赛规则 国际大学生程序设计竞赛(ICPC)作为一项全球性的赛事,其参赛规则通常保持一定的稳定性。根据以往的经验和惯例[^1],每支参赛队伍由三名队员组成,他们需在同一台计算机上合作完成一系列算法问题的解答。比赛期间不允许使用任何外部资源或工具书,仅能依赖团队成员的知识储备以及现场提供的少量参考资料。 对于具体的2024年ICPC网络预选赛而言,虽然官方尚未发布详细的最新规定,但可以推测基本框架不会发生显著变化。例如,在线形式可能继续沿用近年来因疫情而普及的方式;同时也会严格监控作弊行为以维护公平竞争环境[^2]。 #### 时间安排 关于2024年的具体时间表目前还没有确切消息公布出来。然而按照传统模式来看,整个流程一般会经历以下几个阶段: - **报名期**:预计会在年初开放注册通道供各高校提交候选名单。 - **区域选拔赛/网络挑战赛**:这通常是多轮次举行,覆盖不同大洲和地区的时间段以便更多选手参与进来体验实战氛围并争取晋级机会。 - **全球总决赛准备阶段**:成功突围进入最终环节者将获得额外培训指导来提升实力迎接巅峰对决时刻。 以下是基于历史数据猜测的一个大致日程示例(请注意实际日期应参照官方通知为准): | 阶段 | 开始日期 | 结束日期 | |--------------------|---------------|----------------| | 报名截止 | 2024-02-15 | | | 初步筛选结果公告 | | 2024-03-01 | | 第一轮网络资格赛 | 2024-03-10 | 2024-03-12 | | 复活赛 | 2024-04-07 | 2024-04-09 | | 半决赛分区 | 各区自行决定 | 各区自行决定 | #### 题目解析 由于正式试题还未出炉之前无法提供针对性分析,不过可以根据往届经典案例来进行一些通用技巧分享: ```python def example_problem(): """ 假设有一道简单的字符串匹配问题. 给定两个长度不超过1e6 的字符串S 和T(S >= T),判断是否存在子串使得两者完全一致. 如果存在返回True;否则False. """ from collections import defaultdict def kmp_preprocess(pattern): lps = [0]*len(pattern) j=0;i=1; while i<len(pattern): if pattern[i]==pattern[j]: lps[i]=j+1;j+=1;i+=1; elif j!=0: j=lps[j-1]; else : lps[i]=0;i+=1 return lps; s="abcde";t="bcd"; lps=kmp_preprocess(t); q=[]; res=False; for char in s: while(q and (not t[len(q)]==char)): last=len(q)-lps[-1];q=q[:last]; if not q or t[len(q)]==char:q.append(char); if ''.join(q)==t:res=True;break; print(res) example_problem() ``` 上述代码片段展示了一个利用KMP算法解决字符串查找的经典方法之一。当然这只是众多可能性中的很小一部分而已。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值