Takahashi‘s Anguish(AtCoder - abc256_e)

文章目录

题意

现在你要给n个人分糖果,但是他们么个人都有一个嫉妒的人而且还有一个嫉妒值,比如现在有两个人a、b,那么人肯定不会自己嫉妒自己,那么他们两个会相互嫉妒,那么如果你先给a一个糖果那么b会嫉妒,反之b会嫉妒。那么你要确定一个给糖果的顺序保证所产生的嫉妒值之和最小。

思路

首先我们将n个人的嫉妒关系抽象成一个有向图,那么我们就会发现这个图至少会产生一个环,那么我们找出这个图中所有的环的有哪些点,我们只要找出每个环中最小的嫉妒值,再相加就是我们的答案。
在这里插入图片描述
由样例2我们就可以发现将会产生两个环,所以我们分别找出这两个环中最小的嫉妒值,第一个人和第五个人,那么我们一定可以找到一种排列只加上这两个人的嫉妒值,所以采用dfs跑图,值得注意的是当我们跑过的点记得打上标记以免使答案冗余。

因为我们找的只是环中的点,所以dfs只是跑这个图当我们发现一个点跑了两遍那么就已经产生了一个环,所以我们再跑一遍dfs以这个跑了两次的点为起点然后跑的过程中的这些点就是我们这个环中的点,记得打上标记。

代码

#include<bits/stdc++.h>

#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long 

using namespace std;

const int N = 2e5 + 10;

int h[N], idx, n;
int x[N], c[N];
bool st[N], st2[N];
int st1[N];
map<int, int> mp;

struct node
{
	int u, v;
}e[N];

void add(int u, int v)
{
	e[++idx].v = v;
	e[idx].u = h[u];
	h[u] = idx;
}

vector<int> vc, ve;
int ans;

void dfs2(int u)//跑环
{
	if (st2[u])
	{
		int res = ve.size();
		int re = 1e9 + 10;
		int cnt = 0;
		for (int i = 0; i < ve.size(); i++)
			re = min(re, c[ve[i]]);
		ans += re;
		return;
	}
	st2[u] = 1;
	ve.push_back(u);
	for (int i = h[u]; i; i = e[i].u)
	{
		int v = e[i].v;

		dfs2(v);
	}
	ve.pop_back();
}

void dfs(int u, int cnt)//最开始的跑图
{
	if (st[u])
	{
		dfs2(u);
		return;
	}
	st[u] = 1;
	mp[u] = cnt;
	vc.push_back(u);
	for (int i = h[u]; i; i = e[i].u)
	{
		int v = e[i].v;

		if (mp.count(v))
		{
			if (mp[v] != cnt) return;//这个点已经被跑过了,不需要再跑了
		}

		mp[v] = cnt;
		dfs(v, cnt);
	}
	vc.pop_back();
}

signed main()
{
	IOS;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		int x;
		cin >> x;
		add(i, x);//链式前向星存图
	}

	for (int i = 1; i <= n; i++) cin >> c[i];
	int cnt = 0;//标记
	for (int i = 1; i <= n; i++)
	{
		if (!st[i]) cnt++, dfs(i, cnt);
	}
	cout << ans << endl;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值