1009 猫鼠交换
解析:一道典型的贪心算法的题,类似于背包问题,先按单价从小到大排序,再从最便宜的开始买,每次都买的尽可能多。
#include <iostream>
#include<algorithm>
using namespace std;
struct greedheart
{
double value;
double JavaBean;
double CatFood;
};
bool compare(greedheart room1,greedheart room2)
{
return room1.value>room2.value;
}
int main()
{
int m,n;
struct greedheart room[10010];
while((cin>>m>>n)&&(m!=-1)&&(n!=-1))
{
double thentotal=m;
double sum=0;
for(int i=0;i<n;i++)
{
cin>> room[i].JavaBean >> room[i].CatFood;
room[i].value = room[i].JavaBean / room[i].CatFood;
}
sort(room,room+n,compare);
for(int i=0;i<n;i++)
{
if(thentotal < room[i].CatFood)
{
sum += (thentotal/room[i].CatFood)*room[i].JavaBean;
thentotal -= room[i].CatFood;
break;
}
else if(thentotal >= room[i].CatFood)
{
sum += room[i].JavaBean;
thentotal -= room[i].CatFood;
}
}
printf("%.3lf\n",sum);
}
}
心得:贪心算法的题很常见也很重要,一定要理解并多练习,保证熟练度。
1010 迷宫问题
题目理解:在一个迷宫内设置一个起点和一个终点,并在迷宫内设置若干个墙壁,在输入一个步数,判断是否能在这个步数之类到达终点。
解析:本题可以利用BFS深度遍历,遍历每一条路径,然后再将能到达终点的路径和输入步数相比较,判断是否相等。
#include "iostream"
#include "cstring"
using namespace std;
const int maxn = 13;
char a[maxn][maxn];
int vis[maxn][maxn];
int T, n, m, final, sx, sy, ex, ey;
int dx[]={1, -1, 0, 0};
int dy[]={0, 0, 1, -1};
void dfs(int x, int y, int step){
if (step > T) return;
if (a[x][y] == 'D' && step == T) final = 1;
if (final) return;
int left = T - step, les = abs(x - ex) + abs(y - ey);
if (left < les) return;
if (left % 2 != les % 2) return;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if (a[nx][ny] == 'X') continue;
if (vis[nx][ny]) continue;
vis[nx][ny] = 1;
dfs(nx, ny, step + 1);
vis[nx][ny] = 0;
}
}
int main(){
while(scanf("%d%d%d", &n, &m, &T) != EOF && n){
final = 0;
for(int i = 0; i < n; i++) scanf("%s", a[i]);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
if (a[i][j] == 'S') sx = i, sy = j, vis[i][j] = 1;
else if (a[i][j] == 'D') ex = i, ey = j, vis[i][j] = 0;
else if (a[i][j] == 'X') vis[i][j] = 1;
else vis[i][j] = 0;
}
dfs(sx, sy, 0);
if(final) puts("YES");
else puts("NO");
}
return 0;
}
心得:也是很常见一类迷宫题,之前看到这种题并没有去理解它的作法,完成这道题后感觉对深度遍历算法和迷宫问题的理解都得到了一个提升。本题中,还用到了奇偶减枝 http://blog.youkuaiyun.com/nvliba/article/details/48532709中讲的非常容易理解。
1011 士兵找母虫
题意:理解起来比较难,大致就是用最小的代价找到最大的母虫数。
解析:也是用到了DFS深度搜索,但再此之上,还用到了动态规划,我们先定义dp[m][n]表示用n个士兵占领以m为根节点的子树所能获得的概率的最大值,f[m][n] = max {f[m][n], f[m][n - k] + f[v][n] },其中v是m的子节点,这样便写出了动态方程。
#include<stdio.h>
#include<string.h>
typedef struct room
{
int bug, po;
} room;
room R[110];//记录原始数据
int vis[110], next[110], n, m, tree[110][110];
int dp[110][110];//dp[i][j]代表以第i个节点为根节点的树在拥有j个士兵的情况下所能获得首脑的最大概率
int Max(int x, int y)
{
return x>y?x:y;
}
void dfs(int a)
{
int i, j, k, cost;
vis[a] = 1;
cost = (R[a].bug + 19) / 20;//记录该节点所需要的士兵个数
for(i = cost; i <= m; ++i)//初始化该节点能获得的概率
dp[a][i] = R[a].po;
for(i = 0; i <= next[a]; ++ i)
{
int b = tree[a][i];//子节点的编号
if(!vis[b])
{
dfs(b);//求子节点能获得的最大概率
for(j = m; j >= cost; --j)//回溯求父节点的最大概率
for(k = 1; j+k <= m; ++k)
{
if(dp[b][k])//如果说子节点有概率存在,更新父节点的值
dp[a][j+k] = Max(dp[a][j+k], dp[a][j] + dp[b][k]);
}
}
}
return ;
}
int main()
{
int i, j, k;
while(scanf("%d%d", &n, &m) != EOF && ( n!= -1 || m != -1))
{
for(i = 1; i <= n; ++i)//编号从1开始
scanf("%d%d", &R[i].bug, &R[i].po);
memset(next, -1, sizeof(next));
for(i = 0; i < n-1; ++i)
{
int a, b;
scanf("%d%d", &a, &b);
tree[a][++next[a]] = b;//next数组保存节点的子节点的个数
tree[b][++next[b]] = a;//tree保存该节点的子节点的编号
}
if(!m )
{
printf("0\n");
}
else
{
memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
dfs(1);
printf("%d\n", dp[1][m]);
}
}
return 0;
}
心得:题目翻译起来比较复杂,还是需要先把题目意思理解清楚再去做题。动态规划和深度搜索相结合,对我来说还是难度比较大的。
1012 数学公式
解析:本题是一道很基础的计算数学公式题,定义好公式即可。
#include<stdio.h>
#include<iostream>
#define For(i,m,n) for(i=m;i<n;i++)
using namespace std;
int main()
{
double a[10];
double sum=1;
int i;
a[0]=1;
For(i,1,10)
{
sum=sum*i;
a[i]=a[i-1]+1/sum;
}
printf("n e\n");
printf("- -----------\n");
For(i,0,10)
{
if(i>2)
printf("%d %.9lf\n",i,a[i]);
else
cout<<i<<" "<<a[i]<<endl;
}
return 0;
}
心得:基础题