您的位置:首页 > 其它

uva 1016 - Silly Sort(置换的灵活应用)

2013-09-13 09:34 288 查看
题意:给你n个不同数,可以进行一种操作,交换任意两个数的位置,则花费为两数的和,求把原序列变为严格单调递增的序列的最小花费

解析:通过置换可以发现原序列可以分为多个周期(循环)的变换,如8 4 5 3 2 7 变为(8 2 7)和(4 3 5),对于每个周期,所有数都不在他升序后的位置,即所有的数都需要交换,每次用周期内最小的数与另一个数交换,设这个周期的最小值为min,数量为size,所有数的和为sum ,则易得最小花费为min*(size-1)+sum-min,这样得到的花费就是最小值了

但需注意的是在进行变换时,我们可以先把 所有数的最小值Min 和min先交换,当这个周期成升序后再交换回来,则花费为2*(min+Min)+sum-min+(size-1)*Min 比较两者最小值即答案

//保存周期

#include<iostream>
#include<cstdio>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;

#define N 10005
int k,n,a
,c
,b
,vis
,minx;
long long res;
vector<int> w
;

void inint()
{
int i,j;
minx=N*2;
for(i=0;i<N;i++)
w[i].clear();
for(i=0; i<n; i++)
{
scanf("%d",&a[i]);
c[i]=a[i];
}
sort(c,c+n);
minx=c[0];
for(i=n-1; i>=0; i--)
{
b[c[i]]=a[i];
}
memset(vis,0,sizeof(vis));
for(i=0; i<n; i++)
{
j=c[i];
while(!vis[j])
{
vis[j]=1;
w[k].push_back(j);
j=b[j];
}
k++;
}

}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("outw.txt","w",stdout);
int i,j,s,min,qq=0,t=0;
while(~scanf("%d",&n)&&n)
{
res=k=0;
inint();
for(i=0; i<k; i++)
{
s=w[i].size();
if(s<=1) continue;
min=2*N;
for(j=0;j<s;j++)
{
res+=w[i][j];
if(w[i][j]<min) min=w[i][j];
}
res-=min;
if(min!=minx&&min*(s-1)>(s+1)*minx+2*min)
res+=(s+1)*minx+2*min;
else res+=(s-1)*min;
}
t++;
// if(t>=2) puts("");
printf("Case %d: %lld\n\n",t,res);
}
return 0;
}


//直接求答案 快些

#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>

using namespace std;

int a[100000];
int b[100000];
bool vis[100000];

int main (void)
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int N;
int t = 0;
while (~scanf("%d", &N) && N)
{
t++;
for (int i = 0; i < N; ++i)
{
scanf("%d", &a[i]);
b[i] = a[i];
vis[i] = false;
}
sort(b, b + N);
// Map the numbers to their desired place after sort
map<int, int> place;
for (int i = 0; i < N; ++i)
{
place[b[i]] = i;
}

int res = 0;
for (int i = 0; i < N; ++i)
{
if (vis[i] == false)
{
if (place[a[i]] == i)
{
vis[i] = true;
continue;
}
// We're in new cycle
int min_val = a[i];
int num = 0;
int sum = 0;
int j = i;
while (vis[j] == false)
{
sum += a[j];
num++;
if (a[j] < min_val)
{
min_val = a[j];
}
vis[j] = true;
j = place[a[j]];
}
sum -= min_val;
res += sum ;
// Let's try to borrow the minimum value.
// If it's less costly then update our result.
if (2 * (b[0] + min_val) <(min_val - b[0]) * (num - 1))
{
res += ( b[0]) * (num - 1) +2 * (b[0] + min_val);
}
else res+=(num-1)*min_val;
}
}
printf("Case %d: %d\n\n", t, res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: