Scorpio's Trial F-6 HDU-1016 && G-7 HDU-1026 && H-8 UVA-11264 && I-9 HDU-2068 &&J-0 HDU-1166

Problem Description

A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.

Note: the number of first circle should always be 1.

Input

n(0<n<20) .

Output

The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.

You are to write a program that completes above process.

Print a blank line after each case

Sample Input

6

8

Sample Output

Case 1:

1 4 3 2 5 6

1 6 5 2 3 4

Case 2:

1 2 3 8 5 6 7 4

1 2 5 8 3 4 7 6

1 4 7 6 5 8 3 2

1 6 7 4 3 8 5 2

题意:输入n(0<n<20),使1到n个数组成一个素数环(即相邻的两个数之和为素数),依次输出所有的组成方法
题解:经典回溯问题,读懂模板原理即可。

下面给出AC代码:

#include <iostream>
using namespace std;
static int j = 1;
int n, a[20];
bool prime[40], vis[20];

bool is_prime(int m) {
	if (m == 1)
		return false;
	for (int i = 2; i*i <= m; i++)
		if (m % i == 0) return false;
	return true;
}

void dfs(int cur) {
	if (cur == n && prime[a[0] + a[n - 1]]) {
		for (int i = 0; i < n; i++) {
			cout << a[i];
			if (i < n - 1)
				cout << ' ';
			else
				cout << endl;
		}
	}
	else for (int i = 2; i <= n; i++)
		if (!vis[i] && prime[i + a[cur - 1]]) {
			a[cur] = i;
			vis[i] = 1;
			dfs(cur + 1);
			vis[i] = 0;
		}
}

int main()
{
	memset(a, 0, sizeof(a));
	memset(prime, false, sizeof(prime));
	memset(vis, false, sizeof(vis));
	for (int i = 1; i < 40; i++)
		prime[i] = is_prime(i);
	while (cin>>n&&n)
	{
		a[0] = 1;
		cout << "Case " << j++ << ":\n";
		dfs(1);
		cout << endl;
	}
}

                                                            Ignatius and the Princess I

Problem Description

The Princess has been abducted by the BEelzebub feng5166, our hero Ignatius has to rescue our pretty Princess. Now he gets into feng5166's castle. The castle is a large labyrinth. To make the problem simply, we assume the labyrinth is a N*M two-dimensional array which left-top corner is (0,0) and right-bottom corner is (N-1,M-1). Ignatius enters at (0,0), and the door to feng5166's room is at (N-1,M-1), that is our target. There are some monsters in the castle, if Ignatius meet them, he has to kill them. Here is some rules:

1.Ignatius can only move in four directions(up, down, left, right), one step per second. A step is defined as follow: if current position is (x,y), after a step, Ignatius can only stand on (x-1,y), (x+1,y), (x,y-1) or (x,y+1).
2.The array is marked with some characters and numbers. We define them like this:
. : The place where Ignatius can walk on.
X : The place is a trap, Ignatius should not walk on it.
n : Here is a monster with n HP(1<=n<=9), if Ignatius walk on it, it takes him n seconds to kill the monster.

Your task is to give out the path which costs minimum seconds for Ignatius to reach target position. You may assume that the start position and the target position will never be a trap, and there will never be a monster at the start position.

Input

The input contains several test cases. Each test case starts with a line contains two numbers N and M(2<=N<=100,2<=M<=100) which indicate the size of the labyrinth. Then a N*M two-dimensional array follows, which describe the whole labyrinth. The input is terminated by the end of file. More details in the Sample Input.

Output

For each test case, you should output "God please help our poor hero." if Ignatius can't reach the target position, or you should output "It takes n seconds to reach the target position, let me show you the way."(n is the minimum seconds), and tell our hero the whole path. Output a line contains "FINISH" after each test case. If there are more than one path, any one is OK in this problem. More details in the Sample Output.

Sample Input

5 6
.XX.1.
..X.2.
2...X.
...XX.
XXXXX.
5 6
.XX.1.
..X.2.
2...X.
...XX.
XXXXX1
5 6
.XX...
..XX1.
2...X.
...XX.
XXXXX.

Sample Output

It takes 13 seconds to reach the target position, let me show you the way.

1s:(0,0)->(1,0)

2s:(1,0)->(1,1)

3s:(1,1)->(2,1)

4s:(2,1)->(2,2)

5s:(2,2)->(2,3)

6s:(2,3)->(1,3)

7s:(1,3)->(1,4)

8s:FIGHT AT (1,4)

9s:FIGHT AT (1,4)

10s:(1,4)->(1,5)

11s:(1,5)->(2,5)

12s:(2,5)->(3,5)

13s:(3,5)->(4,5)

FINISH

It takes 14 seconds to reach the target position, let me show you the way.

1s:(0,0)->(1,0)

2s:(1,0)->(1,1)

3s:(1,1)->(2,1)

4s:(2,1)->(2,2)

5s:(2,2)->(2,3)

6s:(2,3)->(1,3)

7s:(1,3)->(1,4)

8s:FIGHT AT (1,4)

9s:FIGHT AT (1,4)

10s:(1,4)->(1,5)

11s:(1,5)->(2,5)

12s:(2,5)->(3,5)

13s:(3,5)->(4,5)

14s:FIGHT AT (4,5)

FINISH

God please help our poor hero.

FINISH

参考文章:https://blog.csdn.net/u014422052/article/details/47704897

题意:又是一道看不懂的题目,大概意思是给出n*m的地图,求从(0,0)走到(n-1,m-1)最短时间,方格上的数字表示杀怪所要的时间。
思路:优先队列+bfs,输出路径的时候用一个path数组记录,path[i][j]=d表示(i,j)位置是由d方向过来的。

下面给出AC代码:

#include<iostream>
#include<queue>
using namespace std;
int dir[4][2] = { 0,1,1,0,0,-1,-1,0 };
char map[102][102];
int book[102][102], ans, flag = 0;
int m, n;
struct Path
{
	int x, y, step;
}path[101][101];
struct node
{
	int x; int y;
	int time;
	friend bool operator<(node a, node b)
	{
		return a.time>b.time;
	}
}start;
void show(int a, int b, int t)
{
	if (t == 1)
	{
		cout << t << "s:("<<path[a][b].x << "," << path[a][b].y << ")->(" << a << "," << b << ")\n";
	}
	else if (path[a][b].step == 1)
	{
		show(path[a][b].x, path[a][b].y, t - 1);
		cout << t << "s:(" << path[a][b].x << "," << path[a][b].y << ")->(" << a << "," << b << ")\n";
	}
	else
	{
		--path[a][b].step;
		show(a, b, t - 1);
		printf("%ds:FIGHT AT (%d,%d)\n", t, a, b);
	}
}
void bfs()
{
	memset(book, 0, sizeof(book));
	priority_queue <node> q;
	struct node head, tail;
	start.x = 0;
	start.y = 0;
	start.time = 0;
	book[start.x][start.y] = 1;
	q.push(start);
	int k;
	while (!q.empty())
	{
		head = q.top();
		q.pop();
		if (head.x == n - 1 && head.y == m - 1)
		{
			flag = 1;
			ans = head.time;
			return;
		}
		for (k = 0; k<4; k++)
		{
			tail.x = head.x + dir[k][0];
			tail.y = head.y + dir[k][1];
			if (tail.x >= 0 && tail.y >= 0 && tail.x<n&&tail.y<m&&map[tail.x][tail.y] != 'X'&&book[tail.x][tail.y] == 0)
			{
				if (map[tail.x][tail.y] != 'X')
				{
					if (map[tail.x][tail.y] != '.')
					{
						tail.time = head.time + (map[tail.x][tail.y] - '0') + 1;
						book[tail.x][tail.y] = 1;
						path[tail.x][tail.y].x = head.x;
						path[tail.x][tail.y].y = head.y;
						path[tail.x][tail.y].step = map[tail.x][tail.y] - '0' + 1;
						q.push(tail);
					}
					else if (map[tail.x][tail.y] == '.')
					{
						tail.time = head.time + 1;
						book[tail.x][tail.y] = 1;
						path[tail.x][tail.y].x = head.x;
						path[tail.x][tail.y].y = head.y;
						path[tail.x][tail.y].step = 1;
						q.push(tail);
					}
				}
			}
		}
	}
}
int main()
{
	while (cin>>n>>m)
	{
		int i, j;
		flag = 0;
		for (i = 0; i < n; i++)
		{
			cin >> map[i];
		}
		bfs();
		if (!flag)
		{
			cout << "God please help our poor hero.\nFINISH\n";
		}
		else
		{
			cout << "It takes " << ans << " seconds to reach the target position, let me show you the way.\n";
			show(n - 1, m - 1, ans);
			cout << "FINISH\n";
		}
	}
	return 0;
}

                                                        11264 - Coin Collector

 参考文章:https://blog.csdn.net/xiexingshishu/article/details/42365625

  题意:给出一系列的货币,求出最大的兑换数

思路:sum表示coin[0],coin[1]...coin[i]的和,并且sum[i]<coin[i + 1],如果sum[i] >=coin[i+1],那么coin[i+1]也应该选上,所有相当于找到这样的一个序列s[i-1] < coin[i],并且sum[i] = s[umi-1]+coin[i] < coin[i + 1]

下面给出AC代码:

#include <iostream>
using namespace std;
const int MAXN = 1010;
int coin[MAXN];
int n;
void input()
{
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> coin[i];
	}
}
void solve()
{
	if (n <= 2)
	{
		cout << "2\n";
	}
	else 
	{
		int sum = coin[0];
		int ans = 2;
		for (int i = 1; i < n - 1; i++) 
		{
			if (sum < coin[i] && sum + coin[i] < coin[i + 1])
			{
				sum += coin[i];
				ans++;
			}
		}
		cout << ans << endl;
	}
}
int main()
{
	int cas;
	cin >> cas;
	while (cas--)
	{
		input();
		solve();
	}
}

                                                                RPG的错排

Problem Description

今年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但做为集训队成员之一的野骆驼竟然不知道RPG三个人具体是谁谁。RPG给他机会让他猜猜,第一次猜:R是公主,P是草儿,G是月野兔;第二次猜:R是草儿,P是月野兔,G是公主;第三次猜:R是草儿,P是公主,G是月野兔;......可怜的野骆驼第六次终于把RPG分清楚了。由于RPG的带动,做ACM的女生越来越多,我们的野骆驼想都知道她们,可现在有N多人,他要猜的次数可就多了,为了不为难野骆驼,女生们只要求他答对一半或以上就算过关,请问有多少组答案能使他顺利过关。

Input

输入的数据里有多个case,每个case包括一个n,代表有几个女生,(n<=25), n = 0输入结束。

Sample Input

1

2

0

Sample Output

1

1

题意:了解错排公式,本题为错排加组合数:

下面给出AC代码:

#include<iostream>
#include<cmath>
using namespace std;
#define ll long long int
ll D(int n);
ll D(int n)//錯排公式
{
	if (n == 1)
	{
		return 0;
	}
	if (n == 2)
	{
		return 1;
	}
	else
	{
		return (n - 1)*(D(n - 2) + D(n - 1));
	}
}
ll Cmn(int n, int m)//求組合數,只有本題可以使用
{
	ll sum = 1;
	for (int i = 1; i <= m; i++)
	{
		sum = sum*n / i;
		n--;
	}
	return sum;
}
int main()
{
	int n;
	while (cin>>n && n)
	{
		ll ans = 0;
		if (n == 1 || n == 2)
		{
			cout << "1\n";
			continue;
		}
		else
		{
			int k = n / 2;
			ll ans = 0;
			for (int i = 1; i <= k; i++)
			{
				ans += D(i)*Cmn(n, i);
			}
			cout << ans + 1 << endl;
		}
	}
}

                                                                   敌兵布阵

Problem Description

C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:"你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:"我知错了。。。"但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的.

Input

第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令

Output

对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。

Sample Input

1

10

1 2 3 4 5 6 7 8 9 10

Query 1 3

Add 3 6

Query 2 7

Sub 10 2

Add 6 3

Query 3 10

End

Sample Output

Case 1:
6
33
59

题解:可以用树状数组来做,但这道题没看懂,看别的博客是这么说的:
树状数组 改变区间,求某点

树状数组b[i]表示以i为终点的前  i&(-i)   个数之和

i&(-i)的结果为1      2 3 4 5 6 7 8 9 10 11 12 13 14 15 16....

1 2 1 4 1 2 1 8 1 2 1 4 1 2 1 16...

由上表可以看出

b[1]=a[1];

b[2]=a[1]+a[2];

b[3]=a[3];

b[4]=a[1]+a[2]+a[3]+a[4];

b[5]=a[5];

b[6]=a[5]+a[6];

b[7]=a[7];.......

所以 s[1]=b[1];

s[2]=b[2];

s[3]=b[3]+b[2];

s[4]=b[4];

s[5]=b[5]+b[4];

s[6]=b[6]+b[4];

s[7]=b[7]+b[6]+b[4];

以下代码好像用scanf ,printf才不超时。

#include<iostream>
using namespace std;
const int maxn = 50000 + 10;
struct
{
	int l, r, sum;
}node[maxn * 4];/*空间要开数组大小的4倍,原因请自行搜索*/

int r[maxn], SUM;

void make(int left, int right, int num)//创建线段树   
{
	node[num].l = left;
	node[num].r = right;//记录这个结点表示的范围
	if (left == right)
	{
		node[num].sum = r[left];//处于最底层的叶节点
	}
	else //不是叶节点时
	{
		make(left, (left + right) / 2, num + num);
		make((left + right) / 2 + 1, right, num + num + 1);/*生成左右子树*/
		node[num].sum = node[num * 2].sum + node[num * 2 + 1].sum;//回溯时,当前结点的sum赋值为其左右子结点的sum之和,
																  //查询一定范围的人数的总和时就不必搜到最底层再一个一个加起来,这样就很省时了
	}
}

void query(int left, int right, int num)//查找范围内父节点的和  
{
	if (left <= node[num].l&&right >= node[num].r)
	{
		SUM += node[num].sum;
	}
	else
	{
		if (right <= (node[num].l + node[num].r) / 2)
			query(left, right, num + num);
		else if (left >= (node[num].l + node[num].r) / 2 + 1)
		{
			query(left, right, num + num + 1);
		}
		else
		{
			query(left, right, num + num);
			query(left, right, num + num + 1);
		}
	}
}
void add(int x, int y, int num)/*修改每一个包括改变的那个数的节点*/
{
	node[num].sum += y;
	if (node[num].l == node[num].r)
		return;
	if (x > (node[num].l + node[num].r) / 2)
		add(x, y, num + num + 1);
	else
	{
		add(x, y, num + num);
	}
}

void sup(int x, int y, int num)
{
	node[num].sum -= y;
	if (node[num].l == node[num].r)
		return;
	if (x > (node[num].l + node[num].r) / 2)
		sup(x, y, num + num + 1);
	else
	{
		sup(x, y, num + num);
	}
}

int main()
{
	//freopen("Text.txt", "r", stdin);
	int t, i, a, b, n, m = 0;
	char s[10];
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (int i = 1; i <= n; i++)
		{
			cin >> r[i];
		}
		make(1, n, 1);
		cout<<"Case " << ++m << ":\n";
		while (cin>>s && s[0] != 'E')
		{
			if (s[0] == 'Q')
			{
				cin >> a >> b;
				SUM = 0;
				query(a, b, 1);
				cout << SUM << endl; 
			}
			if (s[0] == 'A')
			{
				cin >> a >> b;
				add(a, b, 1);
			}
			if (s[0] == 'S')
			{
				cin >> a >> b;
				sup(a, b, 1);
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43527358/article/details/86685307