DTOJ 1574:Elephants(slo)

DTOJ 1574:Elephants(slo)

【题目描述】

      对于一个1-N的排列a,每次你可以交换两个数ax与ay,代价为m(ax)+m(ay)
      若干次交换的代价为每次交换的代价之和。请问将a变为b所需的最小代价是多少。
【输入】
      第一行正整数N。2<=N<=1000000
      第二行N个数表示mi。100<=mi<=6500
      第三,四行N个数分别表示排列a和b。1<=ai,bi<=n
【输出】
      仅有一个数,即最少花费。

【样例输入】
6
2400 2000 1200 2400 1600 4000
1 4 5 3 6 2
5 3 2 4 6 1

【样例输出】
11200
【分析】
     两个1-n的不同排列可以视为几个“环”的组合,我们可以将这些“环”分开来讨论。
     若只在环内交换,则需要交换(n-1)次,当取最小值时,应将“环”内的每一个m值各取一遍,剩下的n-2次全部取“环”内m最小值。若用全局最小值来与“环”交换,则在“环”内每个m值的基础上再加一个“环”内最小值和(n+1)和全局最小值。
     将所得的两个值相加,即为当前“环”的答案。
【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000+10;
int n,mmin=1000000000,m[maxn],a[maxn],mp[maxn];
long long ans;
bool f[maxn];
inline int read ( void )
{
	int x=0;char ch=getchar();
	while ( !isdigit(ch) ) ch=getchar();
	while ( isdigit(ch) ) x=(x<<1)+(x<<3)+ch-48,ch=getchar();
	return x;
}
int main()
{
	n=read();
	for ( int i=1;i<=n;i++ ) m[i]=read(),mmin=min(mmin,m[i]);
	for ( int i=1;i<=n;i++ ) a[i]=read();
	for ( int i=1;i<=n;i++ ) mp[a[i]]=read();
	for ( int i=1;i<=n;i++ )
	{
		if ( f[i] ) continue;
		int mn=10000000,t=0,x=i;long long tmp=0;
		while ( !f[x] ) mn=min(mn,m[x]),f[x]=true,tmp+=m[x],t++,x=mp[x];
		ans+=min(mn*(t-2),mmin*(t+1)+mn)+tmp;
	}
	return !printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/dtoi_rsy/article/details/80943015
今日推荐