湖师大ACM校赛总结

湖师大ACM校赛总结

      这是寒假后参加的第一场比赛,是湖南师范大学的校赛,居然是场个人赛!隔了一个寒假,比赛过程很不顺利!并且一直在卡一道题,直到最后也没有A来。不扯了,写份总结吧~~

 

         题目链接:http://acm.hunnu.edu.cn/online/?action=problem&type=list&courseid=55

A题:这就是一道很水的题,计算绩点的题目,如果真的要分类,就是C语言的题目了;

B题:这道题开始没读懂就跳过去了,隔了一小会儿发现很多人都做了,一看,也是C语言的题目;

C题:数论。目前还没有着重学过数论,队友说这题其实不难,以后做了数论在回来看看吧。

D题:搜索,具体点是深搜,这题自己还没有出,也没有着重学这类题目,暂时搁一搁吧。

E题:动态规划题,这道题算不上什么难题,但是赛场上自己一看就以为是KMP,没细看就舍弃了~~

           下面对这道题写个解题报告:

           定义状态:f[i][j]:为关键字key的前i位与数据库中的字串s的前j位匹配结果(bool 型变量

                        f[i][j]为1时表示匹配     

           根据关键字key的不同情况不难得出:

                当key[i]='?'时,f[i][j]=f[i-1][j-1];

                当key='*'时,f[i][j]=f[i-1][j]||f[i][j-1];

                当key[i]为小写字母,则f[i][j]=(f[i-1][j-1])&&(key[i]==s[j]);

               #include using namespace std; char key[51],s[51]; bool dp(){ int m=strlen(key),n=strlen(s); bool f[51][51],flag=1; for(int i=1;i<=m;i++){ //这是本题初始化上的一个细节,可以结合程序尾附的测试数据理解 if(flag && key[i-1]=='*') f[i][0]=1; else f[i][0]=0,flag=0; } for(int i=1;i<=n;i++) f[0][i]=0; f[0][0]=1; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) if(key[i-1]=='*') f[i][j]=f[i-1][j]+f[i][j-1]; else if(key[i-1]=='?') f[i][j]=f[i-1][j-1]; else f[i][j]=(f[i-1][j-1])&(key[i-1]==s[j-1]); return f[m][n]; } int main(){ while(scanf("%s",key)!=-1){ int n,cnt=0; scanf("%d",&n); for(int i=0;i

F题:贪心题。一开始,我把这道题定格成了动归题,够早了很久也没能构造出来状态转移方程。后来想到数据都很小,想到了去模拟装箱的过程。贪心的策略是:拿到一个箱子,想装最大的,大的装不下的时候再去装小的,直到该箱子连最小的都装不下或者最小的都已装完为止。比如:一个6*6的箱子最多装一个6*6的物品就能恰好装满,这当然是最优的装箱方法。接着6*6的物品装完后,装5*5的物品,由于一个6*6的箱子最多容纳一个5*5的物品,这样的话,有多少5*5的物品就需要多少6*6的箱子。是不是这样就可以了呢?当然不是的,每个装5*5的箱子,都还能容纳11(6*6-5*5)个1*1的物品,尽可能多地将1*1的物品放进去就是最有策略。其它的物品,贪心策略类似。

           #include using namespace std; int num[7]; int main(){ while(cin>>num[1]){ int total=num[1]; for(int i=2;i<=6;i++){ cin>>num[i]; total+=num[i]; } if(!total) break; int cnt=0; //开始装6*6的物品 cnt+=num[6]; //6*6物品装箱结束 cnt+=num[5]; //开始装5*5的物品 int left=num[5]*11; if(left>=num[1]) num[1]=0; else num[1]-=left; //5*5的物品装箱结束 cnt+=num[4]; //开始装4*4的物品 left=num[4]*5; if(left>=num[2]){ left=(left-num[2])*4; num[2]=0; if(left>=num[1]) num[1]=0; else num[1]-=left; } else num[2]-=left; //4*4的物品装箱结束 cnt+=num[3]/4; //开始装3*3的物品 cnt++;num[3]%=4; int a[4]={0,5,3,1}; left=a[num[3]]; if(left>=num[2]){ left=36-num[3]*9-num[2]*4; num[2]=0; if(left>=num[1]) num[1]=0; else num[1]-=left; } else{ num[2]-=left; left=36-num[3]*9-left*4; if(left>=num[1]) num[1]=0; else num[1]-=left; } } //3*3的物品装箱结束 cnt+=num[2]/9; //开始装2*2的物品 if(num[2]%9){ cnt++;num[2]%=9; left=36-4*num[2]; if(left>=num[1]) num[1]=0; else num[1]-=left; } //2*2的物品装箱结束 cnt+=num[1]/36; //最后装1*1的物品 if(num[1]%36) cnt++; cout<

G题:计算几何+动态规划。这道题没有做出来还是有原因的,是个通病。就像做E题那样,想当然地把题目定格成了KMP,就束手就擒了。这道题看起来就是计算几何的题目,k个顶点一定是在凸包上,但是如何枚举这k个点,就认为是更高深的计算几何算法而退却了。看了解题报告才知道,其实使用DP来求最大面积的。定义f[i][j][k]为凸包上从下标为i的顶点逆时针方向到下标为j(i,j包含在内)的点中选取k个点作为多边形时的最大面积,容易得出:f[i][j][k]=max{f[i][p][k-1]+area(i,p,j)},其中p为与i,j之间。时间复杂度为O(n^4)。但是本题有一个细节:当凸包上的定点数目小于k的时候,所求结果直接为凸包的面积,而不能采用DP求解!

        #include #include using namespace std; typedef struct Node{ double x,y,ang; }Point; Point p[62],ch[62]; void get_ang(int n){ for(int i=1;ib.y; double d1=dis(a,p[0]),d2=dis(b,p[0]); return d10 && cross(ch[top],p[i],ch[top-1])<=0) top--; ch[++top]=p[i]; } if(cross(ch[top],ch[0],ch[top-1])==0.0) top--; return top+1; } double area(int n){ //求n顶点的多边形面积 double s=0.0; for(int i=1;i>t; while(t--){ cin>>n>>k; for(int i=0;i>p[i].x>>p[i].y; if(n<3 || k<3) cout<<"0.00"<tt) tt=tmp; } f[i][j][r]=tt; if(r==k && f[i][j][r]>res) res=f[i][j][k]; } printf("%.2lf/n",res); } } } return 0; }

H题:RMQ+Union Find Set。这道题是个基本的图论题目,就是判断无向图中任意两个顶点是否连通的问题。RMQ问题一般有两种方法来实现:ST算法和Segment Tree,后来我试了一下,两种算法都是可以过的。就这道题而言,这是一个静态查询的题目,也即相应结点的信息没有动态地进行修改,采用RMQ来实现更高效些,ST算法的复杂度为O(n*logn)的预处理+O(1)的查询,比线段树高效些。

        #include #include # define Max 100001 using namespace std; int index[Max],node[Max],fs[Max][31],fb[Max][31]; int set[Max],rank[Max]; void Init(int n){ //幷查集初始化 for(int i=1;i<=n;i++){ set[i]=i;rank[i]=0; } } int find_set(int x){ //查找 if(x-set[x]) set[x]=find_set(set[x]); return set[x]; } void Union(int x,int y){ // 合并 x=find_set(x);y=find_set(y); if(rank[x]>rank[y]) set[y]=x; else{ if(rank[x]==rank[y]) rank[y]++; set[x]=y; } } void rmq(int n){ //ST算法高效求解静态RMQ问题 for(int i=1;i<=n;i++) fs[i][0]=fb[i][0]=node[i]; int lmt=(int)(log10(n*1.0)/log10(2.0)); for(int i=1;i<=lmt;i++) for(int j=1;j+(1<

 

 

 

 

你可能感兴趣的:(赛后总结)