CF1027Dマウスハント問題の解決策

一言吐きましょう。マウスがひどい怪物に変わったと言われています。怖いですか?本当にあります

トピックを開始します。

明らかに、これはグラフの論文です。

私たちは、意志nnはn部屋はnnとして扱われますn 个点,将 ( i , a i ) (i,a_i) 私はA片側でも。

次に、問題は次のようになります。有向グラフでは、各点の重みはcic_iです。c、エッジに沿ったアクションの過程ですべてのポイントがこれらのポイントに一致するようにいくつかのポイントを選択し、最小の重みの合計を見つけます。

これがリングの最小重量になりませんか?

どうして?

まず、リング(セルフループを含む)の場合、リング上のポイントが選択されていると、他のポイントがこのポイントに到達できます。

では、リングにないものはどうですか?すべてのポイントにはエッジが1つしかないため、リング上にないポイントは常にリング上のポイントに到達できます。

したがって、問題は解決されます。リングを見つけて、最も重みの小さいポイントを取り出します。

ここには2つのアイデアがあります。

  1. ベースリングツリーフォレスト。しかし、私はしません
  2. トポロジカルソート+ユニオン検索セット。

一般的な考え方は、最初にトポロジカルソートを使用して、リング上にないポイントを削除し、残りのポイントをマージし、最小値を取り、合計することです。

コード:

#include <bits/stdc++.h>
#define Min(a, b) ((a < b) ? a : b)
using namespace std;

typedef long long LL;
const int MAXN = 2e5 + 10;
int n, c[MAXN], a[MAXN], cnt[MAXN], fa[MAXN];
LL ans, v[MAXN];
bool book[MAXN];

int read()
{
    
    
	int sum = 0, fh = 1; char ch = getchar();
	while (ch < '0' || ch > '9') {
    
    if (ch == '-') fh = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {
    
    sum = (sum << 3) + (sum << 1) + (ch ^ 48); ch = getchar();}
	return sum * fh;
}

int gf(int x) {
    
    return (fa[x] == x) ? x : (fa[x] = gf(fa[x]));}
void hb(int x, int y) {
    
    if (gf(x) != gf(y)) fa[fa[x]] = fa[y];}

void topsort()
{
    
    
	queue <int> q;
	for (int i = 1; i <= n; ++i)
		if (cnt[i] == 0) {
    
    book[i] = 1; q.push(i);}
	while (!q.empty())
	{
    
    
		int x = q.front();
		q.pop();
		cnt[a[x]]--;
		if (cnt[a[x]] == 0) {
    
    book[a[x]] = 1; q.push(a[x]);}
	}
}

int main()
{
    
    
	n = read();
	for (int i = 1; i <= n; ++i) c[i] = read();
	for (int i = 1; i <= n; ++i) {
    
    cnt[a[i] = read()]++;}
	topsort();
	for (int i = 1; i <= n; ++i) fa[i] = i;
	for (int i = 1; i <= n; ++i)
		if (!book[i] && !book[a[i]]) hb(i, a[i]);
	for (int i = 1; i <= n; ++i) fa[i] = gf(i);
	for (int i = 1; i <= n; ++i) v[i] = 0x7f7f7f7f;
	for (int i = 1; i <= n; ++i) v[fa[i]] = Min(v[fa[i]], c[i]);
	for (int i = 1; i <= n; ++i)
		if (fa[i] == i && !book[i]) ans += (LL)v[i];
	printf("%lld\n", ans);
	return 0;
}

おすすめ

転載: blog.csdn.net/BWzhuzehao/article/details/113756104