24-2-6

 背包

0-1背包

有n个物品,第i个物品的体积为w[i],价值为v[i],每个物品之多选一个,体积和不超过capacity时的最大价值和。

回溯三问

  1. 当前操作?枚举第i个物品选/不选:不选,容量不变;选,剩余容量减少w[i]
  2. 子问题?在剩余容量为c时,从前 i个物品中得到的最大价值和
  3. 下一个子问题?分类讨论:不选:在剩余容量为c时,从前i-1个物品中得到的的最大价值和;选:在剩余容量为c-w[i]时,从前i-1个物品中得到的最大价值和
dfs(i,c)=max(dfs(i-1,c),dfs(i-1,c-w[i])+v[i])
//背包
//记忆化搜索
const int N = 100000;
int cache[N], nums[N], w[N], v[N];
int n, capacity;      //一共有n个物品,背包空间为capacity
int dfs(int i, int c)
{
	if (i < 0)
		return 0;
	if (c < w[i])
		return dfs(i - 1, c);
	return max(dfs(i - 1, c), dfs(i - 1, c - w[i]) + v[i]);
	return dfs(n - 1, capacity);
}

练习题

P9198 「GMOI R2-T1」轴对称

# 「GMOI R2-T1」轴对称

## 题目描述

你有一个 $n$ 行 $m$ 列的图片(矩阵),该图片的像素为 $n\times m$。

初始时,所有像素块均为黑色,RGB 是 $(0,0,0)$。每一次操作可以将一个像素块的 RGB 中的一个数字改变。

在每次操作过后,请你输出图片是否左右对称?

左右对称:即对于任何的 $i,j$,总满足第 $i$ 行第 $j$ 列的像素与第 $i$ 行第 $m-j+1$ 列的像素的 RGB 值相等。

## 输入格式

第一行三个整数 $n,m,q$,$q$ 代表操作次数。

接下来 $q$ 行,每行输入四个整数 $i,j,t,c$,表示将第 $i$ 行第 $j$ 列的格子的 RGB 值的第 $t$ 个数增加 $c$,任何一个 RGB 值的任何一个数如果超出 $255$ 则自动对 $256$ 取模。

## 输出格式

每次操作过后,如果图片左右对称,输出 `Yes`,否则输出 `No`。每组询问的输出之间用换行隔开。

## 样例 #1

### 样例输入 #1

```
6 6 9
1 2 3 4
5 6 3 4
1 5 3 4
5 1 3 4
1 3 2 260
1 4 2 4
2 2 3 5
2 5 3 7
2 2 3 258
```

### 样例输出 #1

```
No
No
No
Yes
No
Yes
No
No
Yes
```

#include<bits/stdc++.h>
using namespace std;
int n, m, a[100][100][4] = { 0 }, q;
int main()
{
	cin >> n >> m >> q;
	while (q--)
	{
		int x, y, t, c, f = 1;
		cin >> x >> y >> t >> c;
		c %= 256;
		a[x][y][t] += c;
		a[x][y][t] %= 256;
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				for (int k = 1; k <= 3; k++)
				{
					if (a[i][m - j + 1][k] != a[i][j][k])
					{
						f = 0;
						break;
					}
				}
				if (!f)
					break;
			}
			if (!f)
				break;
		}
		if (!f)
			puts("No");
		else
			puts("Yes");
	}
	return 0;
}

P5635 【CSGRound1】天下第一

# 【CSGRound1】天下第一

## 题目背景

天下第一的 cbw 以主席的身份在 8102 年统治全宇宙后,开始了自己休闲的生活,并邀请自己的好友每天都来和他做游戏。由于 cbw 想要显出自己平易近人,所以 zhouwc 虽然是一个蒟蒻,也有能和 cbw 玩游戏的机会。

## 题目描述

游戏是这样的:

给定两个数 $x$,$y$,与一个模数 $p$。

cbw 拥有数 $x$,zhouwc 拥有数 $y$。

第一个回合:$x\leftarrow(x+y)\bmod p$。

第二个回合:$y\leftarrow(x+y)\bmod p$。

第三个回合:$x\leftarrow(x+y)\bmod p$。

第四个回合:$y\leftarrow(x+y)\bmod p$。

以此类推....

如果 $x$ 先到 $0$,则 cbw 胜利。如果 $y$ 先到 $0$,则 zhouwc 胜利。如果 $x,y$ 都不能到 $0$,则为平局。

cbw 为了捍卫自己主席的尊严,想要提前知道游戏的结果,并且可以趁机动点手脚,所以他希望你来告诉他结果。

## 输入格式

有多组数据。

第一行:$T$ 和 $p$ 表示一共有 $T$ 组数据且模数都为 $p$。

以下 $T$ 行,每行两个数 $x,y$。

## 输出格式

共 $T$ 行

$1$ 表示 cbw 获胜,$2$ 表示 zhouwc 获胜,```error``` 表示平局。

## 样例 #1

### 样例输入 #1

```
1 10
1 3
```

### 样例输出 #1

```
error
```

## 样例 #2

### 样例输入 #2

```
1 10
4 5
```

### 样例输出 #2

```
1
```

## 提示

$1 \leq T \leq 200$。

$1 \leq x,y,p \leq 10000$。

#include<bits/stdc++.h>
using namespace std;
int t, x, y, mod;
short book[10010][10010];
int func(int x, int y)
{
	if (book[x][y] == -1) return -1;
	if (book[x][y]) return book[x][y];
	book[x][y] = -1;
	if (!x) return book[x][y] = 1;
	if (!y) return book[x][y] = 2;
	int num = (x + y) % mod;
		
	return book[x][y] = func(num, (num % mod + y) % mod);
}
int main()
{
	scanf("%d %d", &t, &mod);
	for (int i = 0; i < t; i++)
	{
		scanf("%d %d", &x, &y);
		int ans = func(x, y);
		if (ans == -1) puts("error");
		else if (ans == 1) puts("1");
		else puts("2");
	}
	return 0;
}

P3367 【模板】并查集

# 【模板】并查集

## 题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

## 输入格式

第一行包含两个整数 $N,M$ ,表示共有 $N$ 个元素和 $M$ 个操作。

接下来 $M$ 行,每行包含三个整数 $Z_i,X_i,Y_i$ 。

当 $Z_i=1$ 时,将 $X_i$ 与 $Y_i$ 所在的集合合并。

当 $Z_i=2$ 时,输出 $X_i$ 与 $Y_i$ 是否在同一集合内,是的输出 
 `Y` ;否则输出 `N` 。

## 输出格式

对于每一个 $Z_i=2$ 的操作,都有一行输出,每行包含一个大写字母,为 `Y` 或者 `N` 。

## 样例 #1

### 样例输入 #1

```
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
```

### 样例输出 #1

```
N
Y
N
Y
```

## 提示

对于 $30\%$ 的数据,$N \le 10$,$M \le 20$。

对于 $70\%$ 的数据,$N \le 100$,$M \le 10^3$。

对于 $100\%$ 的数据,$1\le N \le 10^4$,$1\le M \le 2\times 10^5$,$1 \le X_i, Y_i \le N$,$Z_i \in \{ 1, 2 \}$。

​​​​​​​​​​​​​​

#include<bits/stdc++.h>
using namespace std;
int f[10000], p1, p2, p3;
int getf(int v)
{
	if (f[v] == v)
		return v;
	else
	{
		f[v] = getf(f[v]);
		return f[v];
	}
}
int main()
{
	int n = 0, m = 0;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		f[i] = i;
	for (int i = 1; i <= m; i++)
	{
		cin >> p1 >> p2 >> p3;
		if (p1 == 1)
		{
			f[getf(p2)] = getf(p3);
		}
		else
		{
			if (getf(p2) == getf(p3))
				cout << 'Y' << endl;
			else
				cout << 'N' << endl;
		}
		
	}
	return 0;
}

P1111 修复公路

# 修复公路

## 题目背景

A 地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。

## 题目描述

给出 A 地区的村庄数 $N$,和公路数 $M$,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)。

## 输入格式

第 $1$ 行两个正整数 $N,M$。

下面 $M$ 行,每行 $3$ 个正整数 $x,y,t$,告诉你这条公路连着 $x,y$ 两个村庄,在时间t时能修复完成这条公路。

## 输出格式

如果全部公路修复完毕仍然存在两个村庄无法通车,则输出 $-1$,否则输出最早什么时候任意两个村庄能够通车。

## 样例 #1

### 样例输入 #1

```
4 4
1 2 6
1 3 4
1 4 5
4 2 3
```

### 样例输出 #1

```
5
```

## 提示

$1\leq x, y\leq N \le 10 ^ 3$,$1\leq M, t \le 10 ^ 5$。

#include<bits/stdc++.h>
using namespace std;
struct edge
{
	int fr, to, len;
}ed[20000000];
int n, m, x, y, t, cnt, maxn;
int f[100000];
bool cmp(edge a, edge b)
{
	return a.len < b.len;
}
int getf(int v)
{
	if (f[v] == v)
		return v;
	else
	{
		f[v] = getf(f[v]);
		return f[v];
	}
}
void merge(int u, int v)
{
	int f1 = getf(u);
	int f2 = getf(v);
	if (f1 != f2)
	{
		f[f2] = f1;
	}
	return;
}
int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		f[i] = i;
	}
	for (int i = 1; i <= m; i++)
	{
		cin >> ed[i].fr >> ed[i].to >> ed[i].len;
	}
	sort(ed + 1, ed + m + 1, cmp);
	for (int i = 1; i <= m; i++)
	{
		if (cnt == n - 1)
			break;
		else if (getf(ed[i].fr) == getf(ed[i].to))
			continue;
		merge(ed[i].fr, ed[i].to);
		maxn = max(maxn, ed[i].len);
		cnt++;
	}
	if (cnt == n - 1)
		cout << maxn;
	else
		cout << -1;
	return 0;
}

P1616 疯狂的采药

# 疯狂的采药

## 题目背景

此题为纪念 LiYuxiang 而生。

## 题目描述

LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是 LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

$1$. 每种草药可以无限制地疯狂采摘。

$2$. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

## 输入格式

输入第一行有两个整数,分别代表总共能够用来采药的时间 $t$ 和代表山洞里的草药的数目 $m$。

第 $2$ 到第 $(m + 1)$ 行,每行两个整数,第 $(i + 1)$ 行的整数 $a_i, b_i$ 分别表示采摘第 $i$ 种草药的时间和该草药的价值。

## 输出格式

输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

## 样例 #1

### 样例输入 #1

```
70 3
71 100
69 1
1 2
```

### 样例输出 #1

```
140
```

## 提示

#### 数据规模与约定

- 对于 $30\%$ 的数据,保证 $m \le 10^3$ 。
- 对于 $100\%$ 的数据,保证 $1 \leq m \le 10^4$,$1 \leq t \leq 10^7$,且 $1 \leq m \times t \leq 10^7$,$1 \leq a_i, b_i \leq 10^4$。

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int  N = 1e4 + 5, M = 1e7 + 5;
int w[N], v[N], n, m;
int f[M];
signed main()
{
	cin >> m >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> w[i] >> v[i];
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = w[i]; j <= m; j++)
		{
			f[j] = max(f[j], f[j - w[i]] + v[i]);
		}
	}
	cout << f[m];
	return 0;
}

P1048 [NOIP2005 普及组] 采药

 

# [NOIP2005 普及组] 采药

## 题目描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”


如果你是辰辰,你能完成这个任务吗?

## 输入格式

第一行有 $2$ 个整数 $T$($1 \le T \le 1000$)和 $M$($1 \le  M \le 100$),用一个空格隔开,$T$ 代表总共能够用来采药的时间,$M$ 代表山洞里的草药的数目。

接下来的 $M$ 行每行包括两个在 $1$ 到 $100$ 之间(包括 $1$ 和 $100$)的整数,分别表示采摘某株草药的时间和这株草药的价值。

## 输出格式

输出在规定的时间内可以采到的草药的最大总价值。

## 样例 #1

### 样例输入 #1

```
70 3
71 100
69 1
1 2
```

### 样例输出 #1

```
3
```

## 提示

**【数据范围】**

- 对于 $30\%$ 的数据,$M \le 10$;
- 对于全部的数据,$M \le 100$。

**【题目来源】**

NOIP 2005 普及组第三题

#include<bits/stdc++.h>
using namespace std ;
int w[1005] , v[1005] ;
int f[1005][1005] ;
int main()
{
	int t , m ;
	cin >> t >> m ;
	for(int i = 1 ; i <= m ; ++i)
	{
		cin >> w[i] >> v[i] ;
        for(int j = 1 ; j <= t ; ++j)
		{
			f[i][j] = f[i - 1][j] ;
            if(j >= w[i]) 
				f[i][j] = max(f[i][j], f[i - 1][j - w[i]] + v[i]) ;
        }
    }
    cout << f[m][t] ;
	return 0 ;
}

P1115 最大子段和

# 最大子段和

## 题目描述

给出一个长度为 $n$ 的序列 $a$,选出其中连续且非空的一段使得这段和最大。

## 输入格式

第一行是一个整数,表示序列的长度 $n$。

第二行有 $n$ 个整数,第 $i$ 个整数表示序列的第 $i$ 个数字 $a_i$。

## 输出格式

输出一行一个整数表示答案。

## 样例 #1

### 样例输入 #1

```
7
2 -4 3 -1 2 -4 3
```

### 样例输出 #1

```
4
```

## 提示

#### 样例 1 解释

选取 $[3, 5]$ 子段 $\{3, -1, 2\}$,其和为 $4$。

#### 数据规模与约定

- 对于 $40\%$ 的数据,保证 $n \leq 2 \times 10^3$。
- 对于 $100\%$ 的数据,保证 $1 \leq n \leq 2 \times 10^5$,$-10^4 \leq a_i \leq 10^4$。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int main()
{
	int nums[N], dp[N];
	int n = 0, ans = INT_MIN;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> nums[i];
	}
	dp[0] = nums[0];
	for (int i = 0; i < n; i++)
	{
		dp[i] = max(dp[i - 1] + nums[i], nums[i]);
		if (ans < dp[i])
			ans = dp[i];
	}
	cout << ans;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值