纪中DAY16做题小结

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/ha_ing/article/details/100062989

T1:香烟

Description
你现在有n支香烟。香烟抽完后有香烟蒂头。k个香烟蒂头可以换一支新的香烟。(k > 1)现在一开始有n支香烟,问最多能抽多少支烟?只能利用你现有的烟,不能向别人借烟。

Input
一行,两个整数,n和k。两个整数均在longint范围之内,答案也在longint范围之内。

Output
输出只有一个数, 表示最多能抽多少支烟.

Sample Input

4 3

Sample Output

5

简要思路:这题只是一道简单的模拟题,连小学生都能切掉 ,只要注意用一个变量保存烟头数量,另一个变量保存剩余香烟数量即可。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n , k;
int ans , tem1 , tem2;//tem1剩余香烟数量,tem2烟头数量 
inline void read( int & res ) {
	res = 0;
	int pd = 1;
	char a = getchar();
	while ( a < '0' || a > '9' ) {
		if ( a == '-' ) {
			pd = -pd;
		}
		a = getchar();
	}
	while ( a >= '0' && a <= '9' ) {
		res = ( res << 1 ) + ( res << 3 ) + ( a - '0' );
		a = getchar();
	}
	res *= pd;
	return;
}
int main () {
	read(n);
	read(k);
	ans = n;
	tem1 = n;
	tem2 = tem1 / k;
	while( tem2 ) {
		tem1 %= k;
		tem1 += tem2;
		ans += tem2;
		tem2 = tem1 / k;
	}
	printf("%d",ans);
	return 0;
}

T2:背包问题

Description
从T组物品中选出一些物品,放入背包中,求剩余空间的最小值。
限制条件:从每组物品中挑选物品必须要选取连续的一段。就是说,如果这组物品共有n个: 物品1、物品2、物品3、…、物品n,那么只能选取物品i、物品i+1、…、物品j,其中1<=i<=j<=n,或者不选。

Input
第一行为两个用空格隔开的正整数v和T。表示背包的空间和物品的组数。接下来有T行,每行先是一个正整数ni,表示这组物品有ni个,然后ni个正整数,表示每个物品的大小。

Output
仅一个数,表示剩余空间的最小值。

Sample Input

100 3
3 7 6 8
2 80 70
4 101 108 103 150

Sample Output

6

Hint
【样例说明】
第1组选6、8,第2组选80,第3组不选。
【限制】
60%的数据满足:1 <= ni <= 10
100%的数据满足:1 <= ni <= 100,1<=v<=5000,1<=T<=10

简要思路:这道题很多人给表示背包的数组赋了实际的值,可我用的不是这个方法。我用 f [ i ] [ j ] f[i][j] 来表示将前 i i 组物品放入背包后能否达到占用大小为 j j 的空间,值为1表示可以,为0表示不可以。用 s u m [ i ] [ j ] sum[i][j] 表示第 i i 组物品前 j j 个物品占用的总空间。状态转移方程为 f [ i ] [ j + s u m [ i ] [ l ] s u m [ i ] [ k ] ] = m a x ( f [ i ] [ j + s u m [ i ] [ l ] s u m [ i ] [ k ] ] , f [ i 1 ] [ j ] ) f[i][j + sum[i][l] - sum[i][k]] = max( f[i][j + sum[i][l] - sum[i][k]] , f[i - 1][j] ) ,这里max用来在0和1之间取1。
最后倒序枚举 f [ T ] [ i ] f[T][i] ,遇到的第一个为1的数所对应的 i i 就是本题的答案。

#include <iostream>
#include <cstdio>
#include <cstring> 
using namespace std;
int v , t , tem;
int f[11][5005] , sum[11][105] , n[11];
inline void read( int & res ) {
	res = 0;
	int pd = 1;
	char a = getchar();
	while ( a < '0' || a > '9' ) {
		if ( a == '-' ) {
			pd = -pd;
		}
		a = getchar();
	}
	while ( a >= '0' && a <= '9' ) {
		res = ( res << 1 ) + ( res << 3 ) + ( a - '0' );
		a = getchar();
	}
	res *= pd;
	return;
}
int main () {
	read(v);
	read(t);
	for ( register int i = 0 ; i <= t ; ++i ) {
		f[i][0] = 1;
	}
	for ( register int i = 1 ; i <= t ; ++i ) {
		read(n[i]);
		for ( register int j = 1 ; j <= n[i] ; ++j ) {
			read(tem);
			sum[i][j] = sum[i][j - 1] + tem;
		}
	}
	for ( register int i = 1 ; i <= t ; ++i ) {
		for ( register int j = 0 ; j <= v ; ++j ) {
			for ( register int k = 0 ; k <= n[i] ; ++k ) {
				for ( register int l = k ; l <= n[i] ; ++l ) {
					if ( j + sum[i][l] - sum[i][k] <= v ) {
						f[i][j + sum[i][l] - sum[i][k]] = max( f[i][j + sum[i][l] - sum[i][k]] , f[i - 1][j] );
					}
				} 
			}
		}
	}
	int ans = 0;
	for ( register int i = v ; i >= 0 ; --i ) {
		if ( f[t][i] ) {
			ans = i;
			break;
		}
	}
	printf("%d",v-ans);
	return 0;
}

T3:破碎的路径

Description
比尔去很多地方旅游过。他在旅游的同时留下了很多简短的旅行笔记。笔记的形式是这样的:
出发地 目的地
如下面就是三条合法的note:
SwimmingPool OldTree
BirdsNest Garage
Garage SwimmingPool
在某一次搬家的时候,比尔的笔记本不小心散架了。于是他的笔记的顺序被完全打乱了。他想请你帮个忙,帮他把这些笔记的顺序整理好,先写的笔记在前面。幸运的是,同一个地方比尔至多只去过一次。也就是说,在这些笔记当中,一个地方至多出现两次,一次作为目的地,一次作为出发地。

Input
第一行是一个整数n,表示笔记的条数。N <= 12000。接下来有n行,每行一条笔记。笔记的两个单词的长度都不会超过15,两个单词之间以一个空格分隔。

Output
输出整理好顺序的笔记.

Sample Input

3
SwimmingPool OldTree
BirdsNest Garage
Garage SwimmingPool

Sample Output

BirdsNest Garage
Garage SwimmingPool
SwimmingPool OldTree

Hint
【限制】
对于50%的数据,n <= 1000。
对于100%的数据,n <= 12000。

简要思路:根据题意描述,鉴于旅行的比尔不会飞,再加上他只去一个地方一次,我们不难发现他旅行的路线是一条链,用拓扑大法即可,对于字符串用map即可,也有用哈希的,不过输出时要枚举,时间复杂度稍大。
输出时在jzoj必须将字符串一次输出,不能一个字符一个字符地输出,否则会被误判 ,具体原因我也不知道了(我就这样被坑了100分啊qwq )。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
using namespace std;
int n , bcnt;
string s1 , s2;
map < string , int > f1;
map < int , string > f2;
int inde[15005] , to[15005]; 
int main () {
	scanf("%d",&n);
	for ( int i = 1 ; i <= n ; ++i ) {
		cin >> s1;
		cin >> s2;
		if ( !f1[s1] ) {
			f1[s1] = ++bcnt;
			f2[bcnt] = s1;
		}
		if ( !f1[s2] ) {
			f1[s2] = ++bcnt;
			f2[bcnt] = s2;
		}
		inde[f1[s2]]++;
		to[f1[s1]] = f1[s2];
	}
	int pos = 0;
	for ( int i = 1 ; i <= bcnt ; ++i ) {
		if ( !inde[i] ) {
			pos = i;
			break;
		}
	}
	while ( to[pos] ) {
		cout << f2[pos] << " " << f2[to[pos]] << endl; 
		pos = to[pos];
	}
	return 0;
}

T4:无线网络

Description
有一个由n台计算机组成的无线网络。(n <= 1001),正常情况下,每台计算机都能跟与它距离不超过d的任何计算机通讯(d <= 20000)。地震发生了。所有的计算机都陷入瘫痪。专家们试着一台一台地修复计算机,以恢复整个无线网络。有时在修复的过程中,他们需要测试一下某两台计算机能否通讯(如果他们能通过别的正常的计算机进行通讯,也算他们之间可以通讯,即“能否通讯”可以是间接的)。
你的任务,就是模拟修复网络的过程,并回答“能否通讯”的询问。

Input
第一行两个整数,N和d,N表示计算机的数目,d表示两台计算机直接可直接通讯的最大距离。接下来的N行,每行两个整数Xi,Yi,表示每台计算机的坐标。接下来有许多行,每行都是一个操作(或者是修复操作,或者是询问操作)。
操作的格式如下:
O p (1 <= p <= N) 修复操作,表示修复编号为p的电脑;
S p q (1 <= p, q <= N) 询问操作,询问编号为p和编号为q的电脑能否通讯。
如果一台电脑尚未被修复,则它不能和任何电脑通讯。

Output
对于每个询问操作:如果能够通讯,输出一行SUCCESS;如果无法通讯,输出一行FAIL

Sample Input

4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4

Sample Output

FAIL
SUCCESS

Hint
【限制】
对于50%的数据,N <= 300, 操作次数 <= 10000;
对于100%的数据,N <= 1001, 操作次数 <= 300000。

简要思路:这题用并查集即可,预处理时可以预处理出任两点之间的距离。每当一个点修好后,枚举其他所有点,如果与当前点的距离小于 d d 就将两个点放在一个集合中。在判断两个电脑能否通讯时,除了要判断它们是否在一个集合中,还要注意两个电脑本身是否已修好。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define N 1005
using namespace std;
int fa[N] , p[N];
double dis[N][N];
char ss;
int n , d;
struct node{
	int x;
	int y;
}nod[N];
inline void read( int & res ) {
	res = 0;
	int pd = 1;
	char a = getchar();
	while ( a < '0' || a > '9' ) {
		if ( a == '-' ) {
			pd = -pd;
		}
		a = getchar();
	}
	while ( a >= '0' && a <= '9' ) {
		res = ( res << 1 ) + ( res << 3 ) + ( a - '0' );
		a = getchar();
	}
	res *= pd;
	return;
}
inline int find( int x ) {
	if ( x == fa[x] ) {
		return x;
	} else {
		fa[x] = find( fa[x] );
		return fa[x];
	}
}
inline void unio( int x , int y ) {
	int fx = find(x);
	int fy = find(y);
	if ( fx != fy ) {
		fa[fx] = fy;
	}
	return;
}
inline double cnt( int x1 , int y1 , int x2 , int y2 ) {
	return sqrt( (double)( x2 - x1 ) * (double)( x2 - x1 ) + (double)( y2 - y1 ) * (double)( y2 - y1 ) );
}
int main () {
	scanf("%d%d",&n,&d);
	for ( int i = 1 ; i <= n ; ++i ) {
		fa[i] = i;
		p[i] = 0;
		scanf("%d%d",&nod[i].x,&nod[i].y);
		for ( int j = 1 ; j <= i - 1 ; ++j ) {
			dis[i][j] = dis[j][i] = cnt( nod[i].x , nod[i].y , nod[j].x , nod[j].y );
		}
	}
	int x , y;
	while ( scanf("%c ",&ss) != EOF ) {
		switch(ss) {
			case 'O' : {
				scanf("%d",&x);
				p[x] = 1;//判断电脑是否已修好
				for ( int i = 1 ; i <= n ; ++i ) {
					if ( p[i] && i != x && dis[i][x] <= d ) {
						unio( x , i );
					}
				}
				break;
			}
			case 'S' : {
				scanf("%d%d",&x,&y);
				int fx = find(x);
				int fy = find(y);
				if ( fx == fy && p[x] && p[y] ) {
					printf("SUCCESS\n");
				} else {
					printf("FAIL\n");
				}
				break;
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ha_ing/article/details/100062989
今日推荐