首页 > 其他分享 >搭配买卖题解

搭配买卖题解

时间:2023-08-18 21:23:39浏览次数:33  
标签:10 买卖 vis 搭配 题解 ++ int dfn low

原题

题目描述

joe觉得云朵很美,决定去山上的商店买一些云朵。商店里有n多云,云朵被编号为1,2,……,n,并且每朵云都有一个价值。但商店老板跟他说,一些云朵要搭配来买才好,所以买一朵云则与这多云有搭配的云都要买。但是Joe 的钱有限,所以他希望买的价值越多越好。

输入

1行:nmw,表示n多云,m个搭配,Joe有w的钱

2n+1行,每行cidi表示i朵云的价钱和价值。

n+2n+1+m行,每行uivi表示买ui就必须买vi,同理,如果买vi就必须买ui

输出

一行:表示可以获得的最大价值

样例

样例输入1

5 3 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2

样例输出1

1

题意

 有n个点,每个点有一个价钱ci和一个价值di。有m条边把其中的一些点相连。现在有w的钱,请问最多可以买多少价值的点。


思路

既然是有些点相连,那不就是求连通块、缩点吗?

缩完点后的SCC的价值是连通块内点的价值总和,价钱也是。

再用SCC来跑01背包

样例的图


实现

可以用并查集来储存,然后缩点:

 

for(int i=1; i<=n; i++) {
    int v=find(i);
    if(!vis[v]) {
        cnt++;
		vis[v]=cnt;
	}
	c[vis[v]]+=e[i].x;
	w[vis[v]]+=e[i].y;
}

 

以及我用Tarjan的做法:

 

//标准的Tarjan模板
void tarjan(int x) {
	dfn[x] = low[x] = ++num;
	vis[x] = 1;
	s[++top] = x;
	for (int y : g[x]) {
		if (!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if (vis[y])
			low[x] = min(low[x], dfn[y]);
	}
	if (dfn[x] == low[x]) {
		int y;
		++cnt;
		do {
			y = s[top--];
			vis[y] = 0;
			c[y] = cnt;
		} while (y != x);
	}
}

 

完整代码:

 

#include <bits/stdc++.h>
using namespace std;

const int N = 1e4 + 10;

int n, m, w, f1[N], f2[N], ans = 0;
vector <int> g[N];//存图
int dfn[N], low[N], vis[N], c[N], ff1[N], ff2[N];
int cnt, num, s[N], top;

//标准的Tarjan模板
void tarjan(int x) {
	dfn[x] = low[x] = ++num;
	vis[x] = 1;
	s[++top] = x;
	for (int y : g[x]) {
		if (!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if (vis[y])
			low[x] = min(low[x], dfn[y]);
	}
	if (dfn[x] == low[x]) {
		int y;
		++cnt;
		do {
			y = s[top--];
			vis[y] = 0;
			c[y] = cnt;
		} while (y != x);
	}
}

int main() {
//	freopen("buy.in", "r", stdin);
//	freopen("buy.out", "w", stdout);
	int a, b;
	cin >> n >> m >> w;
	for (int i = 1; i <= n; i++) {
		cin >> f1[i] >> f2[i];
	}
    //读入
	while (m--) {
		cin >> a >> b;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	for (int i = 1; i <= n; i++) 
		if (!dfn[i]) 
			tarjan(i);
	for (int i = 1; i <= n; i++) 
		ff1[c[i]] += f1[i], ff2[c[i]] += f2[i], f1[i] = 0;
	for (int i = 1; i <= cnt; i++) 
		for (int j = w; j >= ff1[i]; j--) //01背包
			f1[j] = max(f1[j], f1[j - ff1[i]] + ff2[i]);
	cout << f1[w];

	return 0;
}

 

标签:10,买卖,vis,搭配,题解,++,int,dfn,low
From: https://www.cnblogs.com/Ji-Siqi/p/17641571.html

相关文章

  • 「BJWC2012」冻结题解
    「BJWC2012」冻结题解一.题目"我要成为魔法少女!""那么,以灵魂为代价,你希望得到什么?""我要将有关魔法和奇迹的一切,封印于卡片之中"在这个愿望被实现以后的世界里,人们享受着魔法卡片(SpellCard,又名符卡)带来的便捷。现在,不需要立下契约也可以使用魔法了!你还不来试一试?比如,我们在......
  • [AGC004D] Teleporter 题解
    简单贪心。思路可以发现一号节点必然连向自己。由于题目中保证了最初每个点都可以到达一号节点。那么我们发现改完一后,原图变成了一棵十分优美的树。考虑在树上进行贪心。我们贪心的从叶子结点往上走。知道第\(k\)个若还没要到\(1\),就直接连向一号节点。这个贪心也比较......
  • 【题解】#119. 最大整数 题解(2023-07-12更新)
    #119.最大整数题解本文章的访问次数为次。Part1提示题目传送门欢迎大家指出错误并私信这个蒟蒻欢迎大家在下方评论区写出自己的疑问(记得@这个蒟蒻)本文已同步至学校网站、博客园。Part2背景本来是不想写这篇题解的,但是由于卡了这个蒟蒻\(1\)整天,故此纪念。Par......
  • CF1575G GCD Festival 题解
    题意给定一个长度为\(n\)的正整数数列\(a\),求\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\gcd\left(a_i,a_j\right)\times\gcd\left(i,j\right)\](\(1\len,a_i\le10^5\))。题解根据欧拉函数的性质,可以得出\[n=\sum\limits_{d\midn}\varphi(d)\]该......
  • [AT_ABC106_C]题解(C++)
    PartIPreface原题目\(\text{(Luogu)}\)原题目\(\text{(AtCoder)}\)PartIISketch给定一个字符串\(s\)以及一个整数\(k\)。该字符串为纯数字串。其中的数字\(x\)会在\(k\)天后变为\(x^{k-1}\)个\(x\)。求出\(10^{15}\)天后,串\(s\)的第\(k\)位是什么......
  • [AT_ABC106_D]题解(C++)
    PartIPreface原题目\(\text{(Luogu)}\)原题目\(\text{(AtCoder)}\)PartIISketch给定正整数\(n,m,q\)。接下来给定\(m\)组\(x_i,y_i\),表示一列列车的起始站和终点站。在接下来给定\(q\)组\(l_i,r_i\)。对于每组询问,回答有多少\(x_i\geql_i\operatorna......
  • [AT_ABC106_B]题解(C++)
    PartIPreface原题目\(\text{(Luogu)}\)原题目\(\text{(AtCoder)}\)PartIISketch给定一个正整数\(N\)。求出\(1\simN\)所有因数个数为\(8\)的数的个数。PartIIIAnalysis先输入\(N\)。遍历\(1\simN\)的每个数,记录每个数的因数个数。若因数个数等于\(8\)......
  • [AT_ABC106_A]题解(C++)
    PartIPreface原题目$\text{(Luogu)}$原题目$\text{(AtCoder)}$PartIISketch给定整数$a,b$,输出$(a-1)\times(b-1)$。$2\leqa,b\leq100$。PartIIIAnalysis运用小学知识,进行平移,把几块地拼接在一起。不难看出长为$a-1$,宽为$b-1$,面积为$(a-1)\tim......
  • [AGC061C] First Come First Serve 题解
    题意有两个长度为\(n\)的正整数列\(A,B\)。表示数\(i\)可以填到\(A_i\)或\(B_i\)两个位置中的一个。问删去空位之后可以形成的排列种数。(\(1\len\le5\times10^5\),\(A_i,B_i\)取遍\(\left[1,2n\right]\))。题解首先可以发现填数的方案数为\(2^n\),发现会计算......
  • 题解:【CF858E】 Tests Renumeration
    题目链接一点模拟下下火。首先一定不能覆盖的,只能一点一点挪。将已经在合法位置上的去掉,剩下的测试分为四类:不碍事的样例测试。不碍事的常规测试。占据了样例测试位置的常规测试。占据了常规测试位置的样例测试。将\(1\simn\)中还未使用的空闲位置记录下来,结论是只需......