[比赛|考试]9.21上午考试

9.21考试

290/300(100,100,90)-rank2

缩索大乐斗

T了一个点(被教练dui了),以后练练卡常技巧
其实我感觉(经历了好几次低分之后)我对自己的要求降低了???

升降梯

不要问我这个名字为什么这么奇怪。 Nescafe 之塔一共有 N 层,升降梯在每层都有一个停靠点。手柄有 M 个控制 槽,第 i 个控制槽旁边标着一个数 Ci,满足 C1<C2<C3<……<CM。如果 Ci>0, 表示手柄扳动到该槽时,电梯将上升 Ci 层;如果 Ci<0,表示手柄扳动到该槽 时,电梯将下降-Ci 层;并且一定存在一个 Ci=0,手柄最初就位于此槽中。注 意升降梯只能在 1~N 层间移动,因此扳动到使升降梯移动到 1 层以下、 N 层以 上的控制槽是不允许的。 电梯每移动一层,需要花费 2 秒钟时间,而手柄从一个控制槽扳到相邻的槽, 需要花费 1 秒钟时间。探险队员现在在 1 层,并且想尽快到达 N 层,他们想知 道从 1 层到 N 层至少需要多长时间?

输入第一行两个正整数 N、 M。 第二行 M 个整数 C1、 C2……CM。 输出一个整数表示答案,即至少需要多长时间。若不可能到达输出-1。

对于 30% 的数据,满足 1≤N≤10, 2<=M<=5。 对于 100% 的数据,满足 1≤N≤1000, 2<=M<=20, -N<C1<C2<……<CM<N

Solution:最短路,把电梯在某一楼层且控制杆在某一位置的状态作为点,状态之间的转移作为边。每一个点有三种转移:操作杆左移,右移,电梯移动。直接dij即可(比SPFA快,tmd这题竟然不卡spfa)

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;

struct fuck
{
	int d, x, y;
	//constructor
	fuck(int d = 0, int x = 0, int y = 0) : d(d), x(x), y(y) {}
};

bool operator>(const fuck &a, const fuck &b)
{
	return a.d > b.d;
}

int N, M, d[1010][25], c[25], src;
bool v[1010][25];

int main()
{
	freopen("elevator.in", "r", stdin);
	freopen("elevator.out", "w", stdout);
	scanf("%d%d", &N, &M);
	for (int i = 1; i <= M; i++)
	{
		scanf("%d", &c[i]);
		if (c[i] == 0)
			src = i;
	}
	priority_queue<fuck, vector<fuck>, greater<fuck> >q;
	q.push(fuck(0, 1, src));
	memset(d, 0x3f, sizeof(d));//????
	d[1][src] = 0;
	while (!q.empty())
	{
		int x = q.top().x, y = q.top().y;
		q.pop();
		if (v[x][y] == true)
			continue;
		v[x][y] = true;
		if (y != 1)//往下扳
		{
			int newy = y - 1;
			if (v[x][newy] == false && d[x][y] + 1 < d[x][newy])
			{
				d[x][newy] = d[x][y] + 1;
				q.push(fuck(d[x][newy], x, newy));
			}
		}
		if (y != M)//往上扳
		{
			int newy = y + 1;
			if (v[x][newy] == false && d[x][y] + 1 < d[x][newy])
			{
				d[x][newy] = d[x][y] + 1;
				q.push(fuck(d[x][newy], x, newy));
			}
		}
		int newx = x + c[y];
		if (newx >= 1 && newx <= N)
		{
			int dis = abs(c[y]) * 2;
			if (v[newx][y] == false && d[x][y] + dis < d[newx][y])
			{
				d[newx][y] = d[x][y] + dis;
				q.push(fuck(d[newx][y], newx, y));
			}
		}
	}
	int ans = 0x3f3f3f3f;
	for (int i = 1; i <= M; i++)
	{
		if (d[N][i] < ans)
			ans = d[N][i];
	}
	if (ans == 0x3f3f3f3f)
		printf("-1\n");
	else
		printf("%d\n", ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

ps:一开始莫名其妙看错题了,以为每次掰杆会自动回复原位,然后就成了lg那道奇怪的电梯了

买鱼

王博退役后开始养鱼。他一早起床就赶去动物园,发现这个世界 的鱼真不少,五光十色、色彩斑斓,大的、小的,什么都有。这些鱼实在是太美 了,买的人越来越多,湖里的鱼越来越少。没有美丽的鱼哪里有美丽的湖?于是动 物园不得不规定,对于每种鱼,每个人最多可以买一条。并且有些鱼不能一起买 的,因为它们之间会相互争斗吞食。 王博想买尽可能多的鱼,但很可惜,他的资金有限。他冥想苦思,不知道如何 是好。请编写一个程序帮助他。如果有多个方案都能买尽可能多的鱼,选择所花 资金最多的一个

输入:从输入文件读入数据。输入文件的第一行为两个正整数 M(M≤l000),N(≤ 30),分别表示 王伯的资金和鱼的种类。以下 N 行,每行有两个正整数 s(1≤S ≤N),T,分别表示某种鱼的编号以及该鱼的价格。 接着,每行有两个正整数 P,Q。当 P,Q 均大于 0 时,表示 P,Q 不能共处;当 P,Q 均等于 0 时,表示输入文件的结束。

输出:输入文件的第一行为两个正整数 X,Y,分别表示所买的鱼的条数和总花费。 以下 X 行,每行有一个正整数,表示所买的鱼的编号。编号按升序排列输出。 如果题目有多个解,输出其中字典序最小的一个。

对于 100%的数据 M≤l000,N≤30

Solution:搜索。xjb乱搜。这种题尽量按照鱼的顺序搜,先把鱼按照编号排序,每次搜鱼,判断是否能够选择,如果可以就把后面冲突的鱼ban++,往下继续搜, 最后再ban回来。注意要先搜选择再搜不选择,这样第一个最优解就是答案。

然后注意可行剪枝:搜索过程中记录价格,限制小于等于M以防王博破产。最优剪枝:如果当前的鱼再买也买不到当前统计的答案那么多直接返回

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;

struct fuck
{
	int id, price;
} a[40];

map<int, int> getid;
int N, M, g[40][40], ban[40];
bool choose[40];

bool cmpid(const fuck &a, const fuck &b)
{
	return a.id < b.id;
}

int maxcnt = 0, maxprice = 0, ans[40];

void search(int x, int totprice, int totcnt)
{
	//最优性剪枝:如果当前再买也买不到当前最大答案那么多了直接返回
	//可行性剪枝:价钱剪枝,保证王博不破产
	if (totcnt + N - x + 1 < maxcnt)
		return;
	if (x == N + 1)
	{
		if (maxcnt < totcnt || (maxcnt == totcnt && maxprice < totprice))
		{
			maxcnt = totcnt;
			maxprice = totprice;
			for (int i = 1; i <= N; i++)
				ans[i] = choose[i];
		}
		return;
	}
	//选择鱼的条件是鱼没有被禁止,并且价格够
	if (ban[x] == 0 && totprice + a[x].price <= M)
	{
		//ban了其它鱼
		choose[x] = true;
		for (int i = x + 1; i <= N; i++)
			if (g[x][i] == true)
				ban[i]++;
		//缩索
		search(x + 1, totprice + a[x].price, totcnt + 1);
		//ban回来
		choose[x] = false;
		for (int i = x + 1; i <= N; i++)
			if (g[x][i] == true)
				ban[i]--;
	}
	search(x + 1, totprice, totcnt);
}

int main()
{
	freopen("fish.in", "r", stdin);
	freopen("fish.out", "w", stdout);
	scanf("%d%d", &M, &N);
	for (int i = 1; i <= N; i++)
		scanf("%d%d", &a[i].id, &a[i].price);
	sort(a + 1, a + 1 + N, cmpid);
	for (int i = 1; i <= N; i++)
		getid[a[i].id] = i;
	int p, q;
	while (2333)
	{
		scanf("%d%d", &p, &q);
		if (p == 0 && q == 0)
			break;
		p = getid[p];
		q = getid[q];
		g[p][q] = g[q][p] = true;
	}
	search(1, 0, 0);
	printf("%d %d\n", maxcnt, maxprice);
	for (int i = 1; i <= N; i++)
	{
		if (ans[i] == true)
			printf("%d\n", a[i].id);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

登山(小猫爬山)

Freda 和 rainbow 饲养了 N 只小猫,这天,小猫们要去爬山。经历了千辛万 苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了

Freda 和 rainbow 只好花钱让它们坐索道下山。索道上的缆车最大承重量为 W,而 N 只小猫的重量分别是 C1、 C2……CN。当然,每辆缆车上的小猫的重量 之和不能超过 W。每租用一辆缆车, Freda 和 rainbow 就要付 1 美元,所以他们 想知道,最少需要付多少美元才能把这 N 只小猫都运送下山?

输入:第一行包含两个用空格隔开的整数, N 和 W。 接下来 N 行每行一个整数,其中第 i+1 行的整数表示第 i 只小猫的重量 Ci。

输出:输出一个整数,最少需要多少美元,也就是最少需要多少辆缆车。

数据范围:对于 100%的数据, 1<=N<=18, 1<=Ci<=W<=10^8

Source:Nescáfe 26杯赛 T1

Solution:首先不难想到一个暴力:枚举全排列,按照排列放猫,然而只有10分

然后呢考虑直接搜索,搜索每一只小猫放在哪个车里或者直接新开一个缆车。

最优形剪枝:如果当前缆车数目大于最小答案,直接return,为了发挥作用,我们需要先搜索把小猫放在原有的车里,再另开一辆车

优化:从大到小sort一遍,可以脑补优化的情形(你先放了大的肯定吼啊)

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;

int N, W, a[25], fuck[25], tot, ans = 0x3f3f3f3f;

void search(int pos)
{
	if (pos == N + 1)
	{
		ans = min(ans, tot);
		return;
	}
	for (int i = 1; i <= tot; i++)
	{
		if (fuck[i] + a[pos] <= W)
		{
			fuck[i] += a[pos];
			search(pos + 1);
			fuck[i] -= a[pos];
		}
	}
	if (tot < ans)
	{
		tot++;
		fuck[tot] = a[pos];
		search(pos + 1);
		tot--;
	}
}

int main()
{
	freopen("climb.in", "r", stdin);
	freopen("climb.out", "w", stdout);
	scanf("%d%d", &N, &W);
	for (int i = 1; i <= N; i++)
		scanf("%d", &a[i]);
	sort(a + 1, a + 1 + N, greater<int>());
	search(1);
	printf("%d\n", ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

orz GMPotlc AK大佬

posted @ 2018-09-22 07:52  ghj1222  阅读(279)  评论(0编辑  收藏  举报