2021-10-03(dfs剪枝优化)

1118. 分成互质组

给定 n 个正整数,将它们分组,使得每组中任意两个数互质。

至少要分成多少个组?

输入格式
第一行是一个正整数 n。

第二行是 n 个不大于10000的正整数。

输出格式
一个正整数,即最少需要的组数。

数据范围
1≤n≤10
输入样例:

6
14 20 33 117 143 175

输出样例:

3
#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int n, a[N], ans = N, len;
vector<int>g[N];
int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}
bool check(int u, int c)
{
	for (int i = 0; i < g[c].size(); i++)
		if (gcd(g[c][i], u) > 1)return false;
	return true;
}
void dfs(int u)
{
	if (u == n)
	{
		ans = min(ans, len);
		return;
	}
	for (int i = 0; i < len; i++)
	{
		if (check(a[u], i))
		{
			g[i].push_back(a[u]);
			dfs(u + 1);
			g[i].pop_back();
		}
	}
	g[len++].push_back(a[u]);
	dfs(u + 1);
	g[--len].pop_back();
}
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)cin >> a[i];
	dfs(0);
	cout << ans << endl;
	return 0;
}

165. 小猫爬山

翰翰和达达饲养了 N 只小猫,这天,小猫们要去爬山。

经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。

翰翰和达达只好花钱让它们坐索道下山。

索道上的缆车最大承重量为 W,而 N 只小猫的重量分别是 C1、C2……CN。

当然,每辆缆车上的小猫的重量之和不能超过 W。

每租用一辆缆车,翰翰和达达就要付 1 美元,所以他们想知道,最少需要付多少美元才能把这 N 只小猫都运送下山?

输入格式
第 1 行:包含两个用空格隔开的整数,N 和 W。

第 2…N+1 行:每行一个整数,其中第 i+1 行的整数表示第 i 只小猫的重量 Ci。

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

数据范围
1≤N≤18,
1≤Ci≤W≤108
输入样例:

5 1996
1
2
1994
12
29

输出样例:

2
#include <bits/stdc++.h>
using namespace std;
const int N = 20;
int n, m;
int w[N];
int sum[N];
int ans = N;
void dfs(int u, int k)
{
	if (k >= ans)return;
	if (u == n)
	{
		ans = k;
		return;
	}
	for (int i = 0; i < k; i++)
	{
		if (sum[i] + w[u] <= m)
		{
			sum[i] += w[u];
			dfs(u + 1, k);
			sum[i] -= w[u];
		}
	}
	sum[k] = w[u];
	dfs(u + 1, k + 1);
	sum[k] = 0;
}
int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)cin >> w[i];
	sort(w, w + n);
	reverse(w, w + n);
	dfs(0, 0);
	cout << ans << endl;
	return 0;
}

1127. 香甜的黄油

农夫John发现了做出全威斯康辛州最甜的黄油的方法:糖。

把糖放在一片牧场上,他知道 N 只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。

当然,他将付出额外的费用在奶牛上。

农夫John很狡猾,就像以前的巴甫洛夫,他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。

他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。

农夫John知道每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。

给出各头牛在的牧场和牧场间的路线,找出使所有牛到达的路程和最短的牧场(他将把糖放在那)。

数据保证至少存在一个牧场和所有牛所在的牧场连通。

输入格式
第一行: 三个数:奶牛数 N,牧场数 P,牧场间道路数 C。

第二行到第 N+1 行: 1 到 N 头奶牛所在的牧场号。

第 N+2 行到第 N+C+1 行:每行有三个数:相连的牧场A、B,两牧场间距 D,当然,连接是双向的。

输出格式
共一行,输出奶牛必须行走的最小的距离和。

数据范围
1≤N≤500,
2≤P≤800,
1≤C≤1450,
1≤D≤255
输入样例:

3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5

输出样例:

8
#include <bits/stdc++.h>
using namespace std;
const int N = 810, M = 3000;
int n, p, m;
int id[N];
int h[N], e[M], ne[M], w[M], idx;
int dist[N], q[N];
bool st[N];
void add(int a, int b, int c)
{
	e[idx] = b;
	w[idx] = c;
	ne[idx] = h[a];
	h[a] = idx++;
}
int spfa(int start)
{
	memset(dist, 0x3f, sizeof dist);
	dist[start] = 0;
	queue<int>q;
	q.push(start);
	while (q.size())
	{
		auto t = q.front();
		q.pop();
		st[t] = false;
		for (int i = h[t]; ~i; i = ne[i])
		{
			int j = e[i];
			if (dist[j] > dist[t] + w[i])
			{
				dist[j] = dist[t] + w[i];
				if (!st[j])
				{
					st[j] = true;
					q.push(j);
				}
			}
		}
	}
	int res = 0;
	for (int i = 0; i < n; i++)
	{
		int j = id[i];
		if (dist[j] == 0x3f3f3f3f)return 0x3f3f3f3f;
		res += dist[j];
	}
	return res;
}
int main()
{
	cin >> n >> p >> m;
	for (int i = 0; i < n; i++)cin >> id[i];
	memset(h, -1, sizeof h);
	for (int i = 0; i < m; i++)
	{
		int a, b, c;
		cin >> a >> b >> c;
		add(a, b, c);
		add(b, a, c);
	}
	int res = 0x3f3f3f3f;
	for (int i = 1; i <= p; i++)res = min(res, spfa(i));
	cout << res << endl;
	return 0;
}

1126. 最小花费

在 n 个人中,某些人的银行账号之间可以互相转账。

这些人之间转账的手续费各不相同。

给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问 A 最少需要多少钱使得转账后 B 收到 100 元。

输入格式
第一行输入两个正整数 n,m,分别表示总人数和可以互相转账的人的对数。

以下 m 行每行输入三个正整数 x,y,z,表示标号为 x 的人和标号为 y 的人之间互相转账需要扣除 z% 的手续费 ( z<100 )。

最后一行输入两个正整数 A,B。

数据保证 A 与 B 之间可以直接或间接地转账。

输出格式
输出 A 使得 B 到账 100 元最少需要的总费用。

精确到小数点后 8 位。

数据范围
1≤n≤2000,
m≤105
输入样例:

3 3
1 2 1
2 3 2
1 3 3
1 3

输出样例:

103.07153164
#include <bits/stdc++.h>
using namespace std;
const int N = 2010;
double dist[N];
bool st[N];
double g[N][N];
int n, m, s, t;
void dijkstra()
{
	dist[s] = 1;
	for (int i = 0; i < n; i++)
	{
		int t = -1;
		for (int j = 1; j <= n; j++)
		{
			if (!st[j] && (dist[t] < dist[j]))
				t = j;
		}
		st[t] = true;
		for (int j = 1; j <= n; j++)
			dist[j] = max(dist[j], dist[t] * g[t][j]);
	}
}
int main()
{
	cin >> n >> m;
	while (m--)
	{
		int a, b, c;
		cin >> a >> b >> c;
		double z = (100.0 - c) / 100;
		g[a][b] = g[b][a] = max(g[a][b], z);
	}
	cin >> s >> t;
	dijkstra();
	printf("%.8f\n", 100 / dist[t]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leimingzeOuO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值