[C++]H106OJ-第三周练习总结

题目一:金属采集

Description

人类在火星上发现了一种新的金属!这些金属分布在一些奇怪的地方,不妨叫它节点好了。一些节点之间有道路相连,所有的节点和道路形成了一棵树。一共有 n 个节点,这些节点被编号为 1~n 。人类将 k 个机器人送上了火星,目的是采集这些金属。这些机器人都被送到了一个指定的着落点, S 号节点。每个机器人在着落之后,必须沿着道路行走。当机器人到达一个节点时,它会采集这个节点蕴藏的所有金属矿。当机器人完成自己的任务之后,可以从任意一个节点返回地球。当然,回到地球的机器人就无法再到火星去了。我们已经提前测量出了每条道路的信息,包括它的两个端点 x 和 y,以及通过这条道路需要花费的能量 w 。我们想花费尽量少的能量采集所有节点的金属,这个任务就交给你了。

Input

第一行包含三个整数 n, S 和 k ,分别代表节点个数、着落点编号,和机器人个数。

接下来一共 n-1 行,每行描述一条道路。一行含有三个整数 x, y 和 w ,代表在 x 号节点和 y 号节点之间有一条道路,通过需要花费 w 个单位的能量。所有道路都可以双向通行。

Output

输出一个整数,代表采集所有节点的金属所需要的最少能量。

Sample Input 1 

6 1 3
1 2 1
2 3 1
2 4 1000
2 5 1000
1 6 1000

Sample Output 1

3004
#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=1e5+100;
struct edge{
 int to,next,w;
}e[maxx<<1];
int dp[maxx][15],head[maxx<<1];
int n,s,k,tot;

inline void init()
{
 memset(head,-1,sizeof(head));
 memset(dp,0,sizeof(dp));
 tot=0;
}
inline void add(int u,int v,int w)
{
 e[tot].next=head[u],e[tot].to=v,e[tot].w=w,head[u]=tot++;
}
inline void dfs(int u,int f)
{
 for(int i=head[u];i!=-1;i=e[i].next)
 {
  int to=e[i].to;
  if(to==f) continue;
  dfs(to,u);
  for(int r=k;r>=0;r--)
  {
   dp[u][r]+=dp[to][0]+2*e[i].w;
   for(int j=1;j<=r;j++) dp[u][r]=min(dp[u][r],dp[u][r-j]+dp[to][j]+j*e[i].w);
  }
 }
}
int main()
{
 scanf("%d%d%d",&n,&s,&k);
 init();
 int x,y,z;
 for(int i=1;i<n;i++)
 {
  scanf("%d%d%d",&x,&y,&z);
  add(x,y,z);
  add(y,x,z);
 }
 dfs(s,0);
 printf("%d\n",dp[s][k]);
 return 0;
}

题目二:铺地毯

Description

为了准备一个学生节,组织者在会场的一片矩形区域(可看做是平面直角坐标

系的第一象限)铺上一些矩形地毯。一共有n 张地毯,编号从1 到n。现在将这些地毯按照

编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。

地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形

地毯边界和四个顶点上的点也算被地毯覆盖。

Input

输入共 n+2 行。

第一行,一个整数 n,表示总共有n 张地毯。

接下来的 n 行中,第i+1 行表示编号i 的地毯的信息,包含四个正整数a,b,g,k,每

两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a,b)以及地毯在x

轴和y 轴方向的长度。

第 n+2 行包含两个正整数x 和y,表示所求的地面的点的坐标(x,y)。

Output

输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出-1。

Sample Input 1 

3
1 0 2 3
0 2 3 3
2 1 3 3
2 2

Sample Output 1

3

思路:

这题,只要把所有的地毯信息都存入数组,然后遍历,如果地毯覆盖部分包含了目标点,则更新存储地毯编号的变量。
判断包含的方法:设任意地毯信息为a,b,g,k,则其覆盖坐标为x:a < x < g + a,y:b < y < k + b。如此判断即可。

#include<iostream>
using namespace std;
const int N = 1e4 + 10;

int n;
int a, b, g, k;
int x, y;
struct loc { int a, b, g, k; };
loc gd[N]; 

int main()
{
	cin >> n;
	for(int i = 1; i <= n; i ++)
	{
		cin >> a >> b >> g >> k;
		gd[i] = {a, b, g, k};
	}
	cin >> x >> y;
	int ret = -1;
	for(int i = 1; i <= n; i ++)
	{
		if(x >= gd[i].a && x <= gd[i].g + gd[i].a)
			if(y >= gd[i].b && y <= gd[i].k + gd[i].b)
				ret = i;
	}
	cout << ret;
	return 0;
}

题目三:扫雷

Description

扫雷游戏你一定玩过吧!现在给你若干个n×m的地雷阵,请你计算出每个矩阵中每个单元格相邻单元格内地雷的个数,每个单元格最多有8个相邻的单元格。 0<n,m<=100

Input

输入包含若干个矩阵,对于每个矩阵,第一行包含两个整数n和m,分别表示这个矩阵的行数和列数。接下来n行每行包含m个字符。安全区域用‘.’表示,有地雷区域用'*'表示。当n=m=0时输入结束。

Output

对于第i个矩阵,首先在单独的一行里打印序号:“Field #i:”,接下来的n行中,读入的'.'应被该位置周围的地雷数所代替。输出的每两个矩阵必须用一个空行隔开。

(注意两个矩阵之间应该有一个空行,由于oj的格式化这里不能显示出来)

Sample Input 1 

4 4
*...
....
.*..
....
3 5
**...
.....
.*...
0 0

Sample Output 1

Field #1:
*100
2210
1*10
1110
Field #2:
**100
33200
1*100

 思路:
1.是否存储输入:不存储,边输入边处理。
2.怎么处理:二维数组初始化为全0,从下标(1,1)的位置开始存储数据,可有效避免数组越界。当读入了一个“地雷”时,即“*”,就直接暴力把周围8个格子中的非地雷格数量加1,同时地雷格子设定为"-1"。然后遍历输出数组,遇到-1,输出星号即可。
3.如何重新开始:重新开始时,要注意清空上一次使用过的数组信息。

#include<iostream>
#include<cstring>
using namespace std;
const int N = 150;

char ch;
int n, m, cnt;
int F[N][N];
int dx[4], dy[4];

int main()
{
	while(cin >> n >> m)
	{
		if(n == 0 || m == 0)
			break;
		for(int i = 1; i <= n; i ++)
		{
			for(int j = 1; j<= m; j ++)
			{
				cin >> ch;
				if(ch == '*')
				{
					F[i][j] = -1;
					if(F[i-1][j-1] != -1) F[i-1][j-1]++;
					if(F[i-1][j] != -1) F[i-1][j]++;
					if(F[i-1][j+1] != -1) F[i-1][j+1]++;
					if(F[i][j-1] != -1) F[i][j-1]++;
					if(F[i][j+1] != -1) F[i][j+1]++;
					if(F[i+1][j-1] != -1) F[i+1][j-1]++;
					if(F[i+1][j] != -1) F[i+1][j]++;
					if(F[i+1][j+1] != -1) F[i+1][j+1]++;
				}
					
			}
		}
		printf("Field #%d:\n", ++cnt);
		for(int i = 1; i <= n; i ++)
		{
			for(int j = 1; j <= m; j ++)
			{
				if(F[i][j] == -1)
					cout << "*";
				else
					cout << F[i][j];
			}
			cout << endl;
		}
		cout << endl;
		memset(F, 0 ,sizeof F);
	}
	return 0;	
} 

题目四:去注释

Description

给你一段C++代码,将其中的注释去除后输出剩余的代码。

注释共有两种形式:

1. 行注视:以//开头,一直作用到行尾为止。

例子:

int n;//n表示数据规模

int a;

去注释后:

int n;

int a;

注意:保留行尾换行符

2. 段注视:以/*开头,到*//结尾,中间部分都是注释,可以跨行。

例子:

int main() {

/*

我是

一段

注释

*/

}

去注释后:

int main() {

}

注意:由于在线评测系统(Online Judge)对网页显示文本作了格式化,一些空行会被删去,导致上面显示的删除后的结果不正确。删除注释后,剩余的代码应该是三行,两行代码之间有一个空行。这是因为:在段注释结尾符的后面有一个换行符,它不在注释内,需要保留。

输入样例:

int main() {

/*

我是

一段

注释

*/

int n;//n表示数据规模

}

Input

一段C++程序代码

输出样例:

int main() {

int n;

}

注意:和之前题目中的解释一样,在int n;之前有一个空行,被在线评测系统删掉,实际程序输出应该有该空行。

Output

去掉注释部分后的程序

思路:

1.怎么读入数据:利用while((ch = cin.get()) != EOF)即可判断输入是否结束。将输入的每一个字节都存入数组,在对数组进行操作。
2.怎么操作:两种方式,删除或者跳跃,删除太麻烦了。直接选择跳跃。
3.怎么跳越:两种注释都有特征。

#include<iostream>
using namespace std;
const int N = 1e5;

int pos;
char ch, code[N];

int main()
{
	while((ch = cin.get()) != EOF)
		code[pos++] = ch;
	code[pos++] = ' ';
	for(int i = 0; i < pos - 1; i ++)
	{
		if(code[i] == '/' && code[i + 1] == '*')
		{
			i += 2;
			for(int j = i; j < pos; j ++)
				if(code[j] == '*' && code[j + 1] == '/')
					i = j, j = pos;
			i += 2;
		}
			
		if(code[i] == '/' && code[i + 1] == '/')
		{
			i += 2;
			while(code[i] != '\n')
				i ++;
		}
		
		cout << code[i];
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值