洛谷P1450.硬币购物

传送门 

题目大意:4种面值c[i]的硬币,每种硬币持有d[i]个,问有多少种方法支付出正好N块钱。

可以先预处理出持有硬币无限的情况dp[n],即一个完全背包问题。

之后根据容斥原理,相当于求\sum_{i=1}^{n}c_{i}x_{i}=S但是拥有限制x_i\leq d_{i},可以参考有限制的不定方程非负整数解的容斥方法,我们设全集U为所有在无限情况下凑出S的方案数,属性为x_i\leq d_{i},那么就可以对所有补集的并用容斥原理展开进行计算,对于每个\left | \bigcap_{a_{i}<a_{i+1}}^{|a|=k}\overline{S_{a_{i}}} \right |是由具有k个不同反向性质x_{i}\geq d_{i}+1组成的集合,对应在容斥式子中的答案就是在无限情况下凑出 \sum_{i=1}^{n}c_{i}x_{i}=m-\sum_{i=1}^{k}c_{i}(d_{a_{i}}+1)的方案数即dp[m-\sum _{i=1}^{k}c_{i}(d_{a_{i}}+1)]*(-1)^{k-1}

最后用全集减去就可以了。

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
//#define int LL
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#pragma warning(disable :4996)
const int maxn = 100010;
const int mod = 1e9 + 7;
const double eps = 1e-8;

LL c[5], N;
LL d[5], S;
LL dp[maxn];

void solve()
{
	memset(dp, 0, sizeof(dp));
	dp[0] = 1;//价格为0时无限硬币组成之方法数
	for (LL i = 1; i <= 4; i++)
	{
		for (LL j = 0; j <= S; j++)
		{
			if (j - c[i] >= 0)
				dp[j] += dp[j - c[i]];
		}
	}
	LL ans = 0;
	for (LL i = 1; i < 16; i++)//枚举集合数1的个数
	{
		LL tmp = S, bit = 0;//1的个数
		for (LL j = 1; j <= 4; j++)
		{
			if ((i >> (j - 1)) & 1)//这一位1
			{
				tmp -= c[j] * (d[j] + 1);
				bit++;
			}
		}
		if (tmp >= 0)
			ans += (bit % 2 ? 1 : -1) * dp[tmp];//用容斥转化为无限制的完全背包情形
	}
	cout << dp[S] - ans << endl;
}

int main()
{
	IOS;
	for (int i = 1; i <= 4; i++)
		cin >> c[i];
	cin >> N;
	for (int i = 0; i < N; i++)
	{
		for (int j = 1; j <= 4; j++)
			cin >> d[j];
		cin >> S;
		solve();
	}

	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现自动检测“coin.png”中硬币的个数,可以按照以下步骤进行: 1. 读取图像文件 使用Matlab的imread函数读取“coin.png”图像文件,将其保存为一个矩阵。 ``` img = imread('coin.png'); ``` 2. 转换为灰度图像 将读入的图像转换为灰度图像。 ``` gray = rgb2gray(img); ``` 3. 二值化处理 对灰度图像进行二值化处理,将图像转换为黑白两色的图像。 ``` threshold = graythresh(gray); bw = imbinarize(gray,threshold); ``` 4. 对图像进行形态学处理 对二值化后的图像进行形态学处理,去除不必要的噪声点和连接不相邻的硬币。 ``` se = strel('disk',5); bw = imclose(bw,se); bw = imfill(bw,'holes'); bw = bwareafilt(bw,[100,inf]); ``` 5. 检测硬币个数 通过bwlabel函数得到二值化后的图像中连通区域的个数,即硬币的个数。 ``` [labels,numLabels] = bwlabel(bw); numCoins = numLabels; ``` 6. 在原图像中显示硬币个数 在原图像中显示检测到的硬币个数。 ``` figure; imshow(img); title(['Number of coins: ', num2str(numCoins)]); ``` 完整代码如下: ``` img = imread('coin.png'); gray = rgb2gray(img); threshold = graythresh(gray); bw = imbinarize(gray,threshold); se = strel('disk',5); bw = imclose(bw,se); bw = imfill(bw,'holes'); bw = bwareafilt(bw,[100,inf]); [labels,numLabels] = bwlabel(bw); numCoins = numLabels; figure; imshow(img); title(['Number of coins: ', num2str(numCoins)]); ``` 运行以上代码,就可以实现自动检测“coin.png”中硬币的个数,并在原图像中显示检测到的硬币个数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值