HDOJ-ACM 1008-1012解答及思路
1008
Problem Description
Input
Output
Sample Input
Sample Output
题目要求
计算电梯的运行时间
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| using namespace std; int upp(int a,int b) { int sum,diff; diff=b-a; sum=6*diff+5; return sum; } int down(int a,int b) { int sum,diff; diff=a-b; sum=4*diff+5; return sum; } int main() { int N,p[105]={0}; while(cin>>N&&(N!=0)) { int sum=0; for(int i=1;i<=N;i++) cin>>p[i]; for(int i=0;i<N;i++) { if(p[i]<p[i+1]) sum+=upp(p[i],p[i+1]); else sum+=down(p[i],p[i+1]); } cout<<sum<<endl; } return 0; }
|
思路
把电梯上升和下降的情况分开考虑即可。
注意事项
电梯不是每一层都停,只有在起始和末尾位置才停5s。
1009
Problem Description
Input
Output
Sample Input
Sample Output
题目要求
老鼠准备了M磅的猫食准备和N个房间的猫进行交换食物,N个房间中第i个房间存贮了J[i]磅的食物,需要F[i]磅的猫食才能交换,老鼠可以付出F[i]×a%磅的猫食即
可换回J[i]×a%磅的食物,求老鼠可以得到的最大食物量。
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| using namespace std; struct Node { double j,f,p; }a[1001]; bool cmp(const Node a,const Node b) { return a.p>b.p; } int main() { int M,N; while(scanf("%d%d",&M,&N)!=EOF&&(M!=-1)&&(N!=-1)) { double sum=0.0; for(int i=0;i<N;i++) { cin>>a[i].j>>a[i].f; a[i].p=a[i].j/a[i].f; } sort(a,a+N,cmp); for(int i=0;i<N;i++) { if(a[i].f<M) { sum+=a[i].j; M-=a[i].f; } else { sum+=a[i].p*M; break; } } printf("%.3lf\n",sum); } return 0; }
|
思路
运用贪心算法,先算出每个房间可以换取javabeen的性价比用sort按照降序排列,从性价比最高的开始交换,全部交换完之后到性价比次之的房间,如果剩余的猫食
不足以全部满足该仓库的需要的猫食,则交换出全部的猫食换取javabeen后结束循环。
注意事项
该代码在G++中超时,在C++中即可AC。算出性价比按照降序排列后从高到低依次交换是本题的关键。
1010
Problem Description
Input
Output
Sample Input
Sample Output
题目要求
输入一个矩阵,“.”代表可以通过,“S”表示起点,“D”表示终点,“X”表示墙,只能横着走或者竖着走,一个地方只可以走一次,问在t时刻能否恰好逃出去
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| using namespace std; char map[9][9]; //地图最多不超过7行7列,又从(1,1)计算,所以开辟9,9 int M,N,T,di,dj; //给定的三个量,以及终点位置 bool escape; //标识逃生成功 int Dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}}; //分别表示左、右、下、上四个方向 void DFS(int si,int sj,int t) { if(si==0||si>N||sj==0||sj>M) //越出边界便不搜索 return; if(si==di&&sj==dj&&T==t) { escape=1; //时间正好的时候才能逃生 return; } int temp=abs(T-t)-(abs(si-di)+abs(sj-dj)); //计算当前到终点的最短路与还需要的时间差,若小于0则路径剪枝 if(temp<0||temp%2==1) //temp如果是奇数的话也要剪枝 return; for(int i=0;i<4;i++) { if(map[si+Dir[i][0]][sj+Dir[i][1]]!='X') { map[si+Dir[i][0]][sj+Dir[i][1]]='X'; //把当前点刷为X DFS(si+Dir[i][0],sj+Dir[i][1],t+1); //搜索该点 if(escape) return; map[si+Dir[i][0]][sj+Dir[i][1]]='.'; //如果搜索不到退出来了,则重新把该点刷为'.' } } } int main() { int si,sj; while((cin>>N>>M>>T)&&!(N==0&&M==0&&T==0)) { int wall=0; for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { cin>>map[i][j]; if(map[i][j]=='S') { si=i,sj=j; } if(map[i][j]=='D') { di=i,dj=j; } if(map[i][j]=='X') wall++; } if(N*M-wall<=T) //路径剪枝,当走完不含墙的迷宫都还不到T时间将不能逃生 { cout<<"NO"<<endl; continue; } escape=0; map[si][sj]='X'; //记得刷为'X' DFS(si,sj,0); if(escape) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
|
思路
本题运用了深度搜索算法和剪枝算法。从(1,1)位置开始输入矩阵,记录下起点和终点的位置和墙的个数,如果走完所有没有的墙的位置后依旧小于时间T,那
么直接路径剪枝,把起点设为墙后进行深度搜素,如果越出边界那么不搜索结束函数,如果时间正好刚好的话escape返回值为1,再计算当前的最短路径如果小于需要
的时间差,那么路径剪枝,temp如果是奇数的话也要进行剪枝,草图如下
两种不同的走法,下面那一种可以控制时间刚好在T时刻。因为差出的是偶数,所以奇数的话要剪枝掉,省掉搜索时间。接下来进行该位置周围四个方向的前进,
如果不是墙的话进入循环,把当前点设为墙后搜索改点,如果成功后返回1,如果搜索不到退出来,那么重新把改点设为“.”。以此类推搜索完所有的点。
注意事项
由于是向四个方面前进,所以map的输入要从(1,1)开始,数组要设置为9行9列,确保搜索数组的时候不会越界。本题也多处运用了剪枝,大大减少了运算时间。
起点要注意在出发后要设置为“X”,在搜索每一个点的时候该点都要设为“X”,搜索结束后重新变回原样。输出的“YES”和“NO”均为大写,本人因为错把NO的O写成了数字
0导致检查了2个多小时,所以注意在书写代码的时候不要粗心。
1011
Problem Description
Input
Output
Sample Input
Sample Output
题目要求
一棵树,有n个结点,每个结点有v个bug,有w的brain。我从1号结点开始走,带着m个战士。1个战士可以消灭20个bugs,如果我把某个结点的所有bug都消灭了我就能
得到那个结点的brain。如果想攻击当前结点,那么必须先攻击了它的父结点(1号点除外)。其中当你攻占了当前结点,你可以分派人手,走向几个不同的子结点,
去攻占更多。也就是说,不是单一的路径。
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| using namespace std; int n,m; int bug[105],brain[105]; int dp[105][105],vis[105]; vector<int>e[105]; void init() { for(int i=0;i<=n;i++) e[i].clear(); memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); } void dfs(int root) { vis[root]=1; int cost=(bug[root]+19)/20; //上取整 for(int i=cost;i<=m;i++) //只要士兵数>=cost,所获宝藏是一样的,都是brain[root] dp[root][i]=brain[root]; for(int i=0;i<e[root].size();i++) { int next=e[root][i]; if(!vis[next]) { dfs(next); for(int k=m;k>=cost;k--) //派出去的士兵最多k-cost,因为至少要留下cost人在父节点 for(int j=1;j<=k-cost;j++) dp[root][k]=max(dp[root][k],dp[root][k-j]+dp[next][j]); } } } int main() { while(cin>>n>>m) { if(n==-1&&m==-1) break; init(); for(int i=1;i<=n;i++) cin>>bug[i]>>brain[i]; for(int i=1;i<=n-1;i++) { int a,b; cin>>a>>b; e[a].push_back(b); e[b].push_back(a); } if(m==0) { cout<<"0"<<endl; continue; } dfs(1); cout<<dp[1][m]<<endl; } return 0; }
|
第二种dfs+dp写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void dfs(int root) { vis[root]=1; for(int i=0;i<e[root].size();i++) { int next=e[root][i]; if(!vis[next]) { dfs(next); for(int k=m;k>=1;k--) //派出去的士兵最多k-cost,因为至少要留下cost人在父节点 for(int j=1;j<=k;j++) ans[root][k]=max(ans[root][k],ans[root][k-j]+dp[next][j]); } } int t=(bug[root]+19)/20; for(int i=t;i<=m;i++) dp[root][i]=ans[root][i-t]+brain[root]; }
|
思路
树形dp问题,由于并未完全理解,所以未能提供思路,待更新。
注意事项
待更新。
1012
Problem Description
Output
Sample Output
题目要求
按照公式输出n为0-9所求出的e
参考AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| using namespace std; int fun(int n) { int sum=1; if(n==0) return 1; for(int i=1;i<=n;i++) sum*=i; return sum; } double fun2(int n) { double e=0.0; for(int i=0;i<=n;i++) e+=1.0/fun(i); return e; } int main() { cout<<"n e"<<endl<<"- -----------"<<endl; for(int i=0;i<=9;i++) { if(i<=1) printf("%d %.0lf\n",i,fun2(i)); if(i==2) printf("%d %.1lf\n",i,fun2(i)); if(i>2) printf("%d %.9lf\n",i,fun2(i)); } return 0; }
|
思路
按照题目要求写出函数即可。
注意事项
注意输出格式,如果对输出位数有苛刻的要求,请用printf输出而不要用iomanip中的setprecision。