30天编程练习(三)

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;    

}

心得:基础题


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值