acm.docx
- 文档编号:6667558
- 上传时间:2023-01-08
- 格式:DOCX
- 页数:38
- 大小:44.15KB
acm.docx
《acm.docx》由会员分享,可在线阅读,更多相关《acm.docx(38页珍藏版)》请在冰豆网上搜索。
acm
算法之初想
涉及算法及例题:
1.搜索:
搜索算法是利用计算机的高性能来有目的地穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。
搜索过程实际上是根据初始条件和扩展规则构造一棵解答树并寻找符合目标状态的节点的过程。
a.深搜:
一般迷宫问题,如HDOJ_1010TempteroftheBone(骨头的诱惑)
b.广搜:
HDOJ_1253胜利大逃亡及ZJU_1148TheGame
c.二分搜索:
对于函数形式:
HDOJ-2899及HDOJ-2199
对于排序——二分查找
广度和深度优先搜索有一个很大的缺陷,就是他们都是在一个给定的状态空间中穷举。
这在状态空间不大的情况下是很合适的算法,可是当状态空间十分大,且不预测的情况下就不可取了。
他的效率实在太低,甚至不可完成。
所以,在这里再次强调“剪枝”!
二分函数逼近法
最简单的函数逼近法~~题目意思很简单
题目大意是:
如图,有一个街道,街道两边平行的有两排房子,一个长为X的梯子和一个长为Y的梯子如图那样放置在街道上.现在已知X,Y的长度和两个梯子的交点离地的高度C,求街道的宽度.
简单的几何分析后,设宽度为W,很快可以得到一个宽度和Y,X,C之间的关系(想直接解出W好像很有困难):
c/sqrt((x*x-w*w))+c/sqrt((y*y-w*w))-1=0-----------F(w);
显然满足这个方程的W即为本题的解;现在我们无法直接解出这个方程,那我们就开始二分查找;
0<W<Z=X>Y?
Y:
X (Z为X,Y中较小的那一个);
我们就从这个范围里面查找答案(答案满足题目要求的精确度即可;
Start=0;end=z;(查找范围)mid=(start+end)/2;(二分的中间值)
如果F(mid)>0;end=mid;mid=(start+end)/2;
否则:
start=mid;mid=(start+end)/2;
这样一直查找下去,直到找到满足题目要求精度的mid即为W;
#include
#include
usingnamespacestd;
doublex,y,c;
doubleCal_f(doublex,doubley,doublec,doublew)
{//F(W)的值;
doubleans;
ans=c/(sqrt(x*x-w*w))+c/(sqrt(y*y-w*w))-1;
returnans;
}
voidCal_w(doublex,doubley,doublec)//二分查找W;
{
doublestart=0,end=x>y?
y:
x;
doublemid=(start+end)/2;
while(fabs(Cal_f(x,y,c,mid)-0)>0.0000001)//精度越高越好,当然满足题目要求就行;
{
if(Cal_f(x,y,c,mid)<0)//二分查找;
start=mid;
else
end=mid;
mid=(start+end)/2;
}
printf("%.3lf\n",mid);
}
intmain(void)
{
while(scanf("%lf%lf%lf",&x,&y,&c)==3)
Cal_w(x,y,c);
return0;
}
Description:
对方程w的二分逼近求解:
1/c=1/1/sqrt((x*x-mid*mid))+1/sqrt((y*y-mid*mid))
#include
#include
#defineEPS0.000001
intmain(void)
{
doublex,y,c;
doublehigh,low,mid;
while(scanf("%lf%lf%lf",&x,&y,&c)==3)
{
high=x>y?
y:
x;
low=0.0;
while(high-low>EPS)
{
mid=(high+low)/2;
if(1/c>(1/sqrt((x*x-mid*mid))+1/sqrt((y*y-mid*mid))))
{
low=mid;
}
else
{
high=mid;
}
}
printf("%.3lf\n",mid);
}
return0;
}
HDOJ-2899
给出函数:
F(x)=6*x7+8*x6+7*x3+5*x2-y*x
其中,实数y满足(0 请输出x在区间[0,100]时函数F(x)的最小值, 结果精确到小数点后4位。 #include #include constdoubleeps=1e-8; doubley; doublecal(doublex) { return42.0*pow(x,6.0)+48.0*pow(x,5.0)+21.0*pow(x,2.0)+10.0*x; } doubleans(doublex) { return6.0*pow(x,7.0)+8.0*pow(x,6.0)+7.0*pow(x,3.0)+5.0*pow(x,2.0)-y*x; } intmain() { intT; doublef,l,mid; scanf("%d",&T); while(T--) { scanf("%lf",&y); if(cal(100.0)-y<=0.0) { printf("%.4lf\n",ans(100.0)); continue; } f=0.0,l=100.0; while(l-f>eps) { mid=(f+l)/2.0; if(cal(mid)-y<0.0) { f=mid; } else { l=mid; } } printf("%.4lf\n",ans(mid)); } return0; } HDOJ-2199 给出方程: 8*x4+7*x3+2*x2+3*x+6=Y 其中,实数Y满足(fabs(Y)<=1e10) 输入: y 请输出x在区间[0,100]的解,结果精确到小数点后4位,如果不存在,则输出Nosolution! 。 #include #include usingnamespacestd; doubleY; doublel,r,m; doublef(doublex) { return8*pow(x,4.0)+7*pow(x,3.0)+2*pow(x,2.0)+3*x+6; } intmain() { intt; scanf("%d",&t); while(t--) { scanf("%lf",&Y); if(f(0)<=Y&&Y<=f(100)) { l=0; r=100; while(r-l>1e-6) { m=(l+r)/2; doubleans=f(m); if(ans>Y) { r=m-1e-7; } else l=m+1e-7; } printf("%.4lf\n",(l+r)/2); } else printf("Nosolution! \n"); } return0; } 2.回溯: 回溯法对解空间作深度优先搜索,因此,在一般情况下用递归方法实现回溯法。 voidbacktrack(intt) {if(t>n)output(x); else for(inti=f(n,t);i<=g(n,t);i++){ x[t]=h(i); if(constraint(t)&&bound(t))backtrack(t+1); } } HDU1530MaximumClique(最大团问题) 给定无向图G=(V,E)。 如果UV,且对任意u,vU有(u,v)E,则称U是G的完全子图。 G的完全子图U是G的团当且仅当U不包含在G的更大的完全子图中。 G的最大团是指G中所含顶点数最多的团。 如果UV且对任意u,vU有(u,v)E,则称U是G的空子图。 G的空子图U是G的独立集当且仅当U不包含在G的更大的空子图中。 G的最大独立集是G中所含顶点数最多的独立集。 对于任一无向图G=(V,E)其补图G=(V1,E1)定义为: V1=V,且(u,v)E1当且仅当(u,v)E。 故U是G的最大团当且仅当U是G的最大独立集。 ProblemDescription GivenagraphG(V,E),acliqueisasub-graphg(v,e),sothatforallvertexpairsv1,v2inv,thereexistsanedge(v1,v2)ine.Maximumcliqueisthecliquethathasmaximumnumberofvertex. Input Inputcontainsmultipletests.Foreachtest: Thefirstlinehasoneintegern,thenumberofvertex.(1 Thefollowingnlineshasn0or1each,indicatingwhetheranedgeexistsbetweeni(linenumber)andj(columnnumber). Atestwithn=0signalstheendofinput.Thistestshouldnotbeprocessed. Output Onenumberforeachtest,thenumberofvertexinmaximumclique. SampleInput 5 01101 10111 11011 01101 11110 0 SampleOutput 4 Source #include #include #include usingnamespacestd; intn; intg[55][55]; intbest; intnum[55]; //intx[maxn];//取决于是否需要最优解.若需要,还要增加一个path[maxn]数组 booldfs(int*adj,inttotal,intcnt) { inti,j,k; intt[55]; if(total==0) { if(best { //for(i=0;i best=cnt; returntrue; } returnfalse; } for(i=0;i { if(cnt+(total-i)<=best) returnfalse; if(cnt+num[adj[i]]<=best) returnfalse; //x[cnt]=adj[i];//路径信息3 for(k=0,j=i+1;j if(g[adj[i]][adj[j]]) t[k++]=adj[j]; if(dfs(t,k,cnt+1)) returntrue; } returnfalse; } intMaximumClique() { inti,j,k; intadj[55]; if(n<=0) return0; best=0; for(i=n-1;i>=0;i--) { //x[0]=i;路径信息1 for(k=0,j=i+1;j if(g[i][j]) adj[k++]=j; dfs(adj,k,1); num[i]=best; } returnbest; } intmain() { while(scanf("%d",&n)! =EOF) { if(n==0) break; for(inti=0;i for(intj=0;j scanf("%d",&g[i][j]); cout< } return0; } 3.图论: a.最短路径——迪杰斯特拉算法 S1到s2的最短路径《C版本》 城市始点编号为1 #include #definemaxnum200 #definemaxint999999 //各数组都从下标1开始 intdist[maxnum];//表示当前点到源点的最短路径长度 intprev[maxnum];//记录当前点的前一个结点 intc[maxnum][maxnum];//记录图的两点间路径长度 intn,line;//图的结点数和路径数 voidDijkstra(intn,intv,int*dist,int*prev,intc[maxnum][maxnum]) { bools[maxnum];//判断是否已存入该点到S集合中 inti,j; for(i=1;i<=n;++i) { dist[i]=c[v][i]; s[i]=0;//初始都未用过该点 if(dist[i]==maxint) prev[i]=0; else prev[i]=v; } dist[v]=0; s[v]=1; //依次将未放入S集合的结点中,取dist[]最小值的结点,放入结合S中 //一旦S包含了所有V中顶点,dist就记录了从源点到所有其他顶点之间的最短路径长度 //注意是从第二个节点开始,第一个为源点 for(i=2;i<=n;++i) { inttmp=maxint; intu=v; //找出当前未使用的点j的dist[j]最小值 for(j=1;j<=n;++j) if((! s[j])&&dist[j] { u=j;//u保存当前邻接点中距离最小的点的号码 tmp=dist[j]; } s[u]=1;//表示u点已存入S集合中 //更新dist for(j=1;j<=n;++j) if((! s[j])&&c[u][j] { intnewdist=dist[u]+c[u][j]; if(newdist { dist[j]=newdist; prev[j]=u; } } } } voidsearchPath(int*prev,intv,intu)//查找从源点v到终点u的路径,并输出 { intque[maxnum]; inttot=1; que[tot]=u; tot++; inttmp=prev[u]; inti; while(tmp! =v) { que[tot]=tmp; tot++; tmp=prev[tmp]; } que[tot]=v; for(i=tot;i>=1;--i) if(i! =1) printf("%d->",que[i]); else printf("%d\n",que[i]); } intmain() {//各数组都从下标1开始 inti,j; ints1,s2; intp,q,len; while(scanf("%d%d",&n,&line)! =EOF)//输入结点数'路径数 { for(i=1;i<=n;++i)//初始化c[][]为maxint for(j=1;j<=n;++j) c[i][j]=maxint; for(i=1;i<=line;++i) { scanf("%d%d%d",&p,&q,&len);//输入p,q两点及其路径长度 if(len { c[p][q]=len; c[q][p]=len;//表示无向图 } } scanf("%d%d",&s1,&s2); for(i=1;i<=n;++i) dist[i]=maxint; for(i=1;i<=n;++i) { for(j=1;j<=n;++j) printf("%8d",c[i][j]); printf("\n"); } Dijkstra(n,s1,dist,prev,c); printf("源点到终点的最短路径长度: %d\n",dist[s2]);//最短路径长度 printf("源点到终点的路径为: ");//路径 searchPath(prev,s1,s2); printf("\n"); } return0; } Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 Input 输入n,m,点的编号是1~n,然后是m行,每行4个数a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。 最后一行是两个数s,t;起点s,终点。 n和m为0时输入结束。 (1〈n〈=1000,0〈m〈100000,s! =t) Output 输出一行有两个数,最短距离及其花费。 如果最短最径不存在,则输出-1-1 SampleInput 32 1256 2345 13 00 SampleOutput 911 Source #include #definemaxnum200 #definemaxint999999 //各数组都从下标1开始 intdist[2][maxnum];//表示当前点到源点的最短路径长度 intc[maxnum][maxnum];//记录图的两点间路径长度 intvw[maxnum][maxnum]; intn,m;//图的结点数和路径数 voidDijkstra(intn,intv,intdist[2][maxnum],intc[maxnum][maxnum]) { ints[maxnum];//判断是否已存入该点到S集合中 inti,j; for(i=1;i<=n;++i) { dist[0][i]=c[v][i]; dist[1][i]=vw[v][i]; s[i]=0;//初始都未用过该点 } dist[0][v]=0; dist[1][v]=0; s[v]=1; //依次从未放入S集合的结点中,取dist[]最小值的结点,放入结合S中 //一旦S包含了所有V中顶点,dist就记录了从源点到所有其他顶点之间的最短路径长度 //注意是从第二个节点开始,第一个为源点 for(i=2;i<=n;++i) { inttmp=maxint; intu=v; //找出当前未使用的点j的dist[j]最小值 for(j=1;j<=n;++j) if((! s[j])&&dist[0][j] { tmp=dist[0][j]; u=j;//u保存当前邻接点中距离最小的点的号码 } s[u]=1;//表示u点已存入S集合中 //更新dist for(j=1;j<=n;++j) if((! s[j])&&c[u][j] { intnewdist=dist[0][u]+c[u][j]; intnewvw=dist[1][u]+vw[u][j]; if(newdist { dist[0][j]=newdist; dist[1][j]=newvw; } elseif(newdist==dist[0][j]&&newvw { dist[1][j]=newvw; } } } } intmain() {//各数组都从下标1开始 inti,j; ints1,s2; intp,q,len; while(scanf("%d%d",&n,&m)! =EOF)//输入结点数'路径数 { if(n==0&&m==0) break; for(i=1;i<=n
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- acm