首页 > 代码库 > 10.15解题报告
10.15解题报告
D:【基本算法—贪心算法】删数问题
- 描述
-
键盘输入一个高精度的正整数n(<=240位),去掉其中任意s个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的n和s,寻找一种方案,使得剩下的数字组成的新数最小。
这道题目我们可以用贪心法则来攻克
既然要每次删除一个数,那我们就需要让每一次都做出一个最好的选择,这样最后我们也就会得到最佳方案
如何每一次都作出最好的选择,也就是每一次都删除第一个比后面数字大得数,因为如果n比n-1大的话,后面再出现此类情况,我们可以保证n在最大的数位上,于是这个步骤我们可以用函数来完成。
void del(){ len=st.size(); while(m--){ int p=0; while(p<len-1&&st[p]<=st[p+1]) p++; st.erase(p,1); len--; } }
这里面我们使用了搜索,由于只要没有找到满足条件的p,p就会++,所以p最后会停在满足条件数的前一位
但是如果找不到满足条件的数字,我们就应该删掉最高位的那一个数字
下面我们应该做的事情就是删除前导零,我们依旧可以用搜索完成,p将会停留在第一个不为零的数字上void pri(){ int p=0; while(p<len-1&&st[p]==‘0‘){ p++; } for(int i=p;i<len;i++) cout<<st[i]; }
F:〖NOIP2008P〗排座椅
- 描述
-
上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来 之后,只有有限的D对同学上课时会交头接耳。同学们在教室中坐成了M行N列,坐在第i行第j列的同学的位置是(i,j),为了方便同学们进出,在教室中设 置了K条横向的通道,L条纵向的通道。于是,聪明的小雪想到了一个办法,或许可以减少上课时学生交头接耳的问题:她打算重新摆放桌椅,改变同学们桌椅间通 道的位置,因为如果一条通道隔开了两个会交头接耳的同学,那么他们就不会交头接耳了。
请你帮忙给小雪编写一个程序,给出最好的通道划分方案。在该方案下,上课时交头接耳的学生的对数最少。这道题也应该是一道贪心算法,因为我们要在有限的改变次数内做出最好的选择。
怎么样才能算是最好选择?
如果我们要在行之间隔出一条通道,那么我们就应该选择两行之间交头接耳人数最多的,在这里开一条通道
如果我们要在列之间隔出一条通道,那么我们就应该选择两列之间交头接耳人数最多的,在这里开一条通道
于是我们需要对每两行和每两列之间交头接耳的人做出排序,并且记录下他们的位置,然后进行选择
void readp(){ cin>>n>>m>>nk>>mk>>d; for(int i=1;i<n;i++) h[i].id=i; for(int i=1;i<m;i++) l[i].id=i; int x1,y1,x2,y2; while(d--){ cin>>x1>>y1>>x2>>y2; if(x1==x2) { if(y1<y2) l[y1].s++; else l[y2].s++; } else { if(x1<x2) h[x1].s++; else h[x2].s++; } } } 读入并且记录下每行每列交头接耳的人数,记录下行号和列号
void work(){ sort(h+1,h+n,cmp); sort(l+1,l+m,cmp); sort(h+1,h+nk+1,cmp1); sort(l+1,l+mk+1,cmp1); for(int i=1;i<=nk;i++) cout<<h[i].id<<" "; cout<<endl; for(int i=1;i<=mk;i++) cout<<l[i].id<<" "; cout<<endl; }
把人数排序,并且由于输出也需要排序,所以我们还要使用函数对结构体进行排序bool cmp(node p,node q){ return p.s>q.s; } bool cmp1(node p,node q){ return p.id<q.id; }
B:〖NOIP2010P〗导弹拦截
- 描述
-
经过11 年的韬光养晦,某国研发出了一种新的导弹拦截系统,凡是与它的距离不超过其工作半径的导弹都能够被它成功拦截。当工作半径为0 时,则能够拦截与它位置恰好相同的导弹。但该导弹拦截系统也存在这样的缺陷:每套系统每天只能设定一次工作半径。而当天的使用代价,就是所有系统工作半径 的平方和。
某天,雷达捕捉到敌国的导弹来袭。由于该系统尚处于试验阶段,所以只有两套系统投入工作。如果现在的要求是拦截所有的导弹,请计算这一天的最小使用代价。只做出了40分的程序
这道题其实就是两个系统工作的最短半径,也就是必定会有导弹刚好落到这两个系统的边缘上,并且没有遗漏,否则这个半径一定可以继续缩短。
通过提示,我们知道可以利用半径的平方和比较大小
int dis(int x1,int y1,int x2,int y2){ return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); }
然后我们需要进行读入void readp(){ cin>>a>>b>>c>>d; cin>>n; for(int i=1;i<=n;i++) cin>>x[i]>>y[i]; }
接着就是要计算出每一次的平方和,然后比较大小,输出最小的那一个void work(){ int minv=10000000; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ int r1=dis(a,b,x[i],y[i]); int r2=0; for(int k=1;k<=n;k++) if(dis(a,b,x[k],y[k])>r1&&dis(c,d,x[k],y[k])>r2) r2=dis(c,d,x[k],y[k]); if(minv>r1+r2) minv=r1+r2; } cout<<minv; }
当然这个程序只能得到40分,因为它使用了三层循环
10.15解题报告