1. 程式人生 > >BSOJ3362 -- 【模擬試題】聰明的農民

BSOJ3362 -- 【模擬試題】聰明的農民

計算交換次數時可以用並查集來做,但是也有一個貪心就是直接換,但是無法證明其正確性。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,f[5005],s[5005];
long long ans,anss;
struct node{int x,p;}a[5005];
bool cmp(node a,node b){return a.x<b.x;}
int get(int x){return f[x]==x?x:f[x]=get(f[x]);}
//向領主上繳的糧食總量最小是第i個人手中數字是第i小和第i大 
int main(){
	freopen("clever.in","r",stdin);
	freopen("clever.out","w",stdout);
	scanf("%d",&n);
	for(int i=1,x,y;i<=n;i++) 
		scanf("%d%d",&x,&y),a[i*2-1].x=x,a[i*2-1].p=i,a[i*2].x=y,a[i*2].p=i;
	sort(a+1,a+2*n+1,cmp);
	for(int i=1;i<=n;i++) f[i]=i,s[i]=1;//並查集,順帶統計每一塊的數量 
	for(int i=1;i<=n;i++){
		ans+=a[i].x*a[2*n-i+1].x;//計算 
		if(a[i].p!=a[2*n-i+1].p){
			//如果當前人手中不是第i小和第i大,就需交換 
		//交換中,若要使交換次數最小,只需使交換的雙方連成塊,最後統計交換次數 
			int x=get(a[i].p),y=get(a[2*n-i+1].p);
			if(x!=y){
				f[x]=y;s[y]+=s[x]; 
			}
		}
	}
	for(int i=1;i<=n;i++) if(f[i]==i) anss+=s[i]-1;//i個人交換(i-1)次 
	cout<<ans<<" "<<anss;
	return 0;
} 
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
using namespace std;
struct node{int val,pos;
}w[1005];
int cnt=0,ans=0,n,sum=0;
bool cmp(node a,node b)
{
	return a.val<b.val;
}
int main(){
//	freopen("clever.in","r",stdin);
//	freopen("clever.out","w",stdout);
	int a,b;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a>>b;
		w[++cnt].val=a,w[cnt].pos=i;
		w[++cnt].val=b,w[cnt].pos=i;
	}
	sort(w+1,w+cnt+1,cmp);
	for(int i=1;i<=cnt/2;i++)
	  ans+=w[i].val*w[cnt-i+1].val;
	cout<<ans;
	for(int i=1;i<=cnt/2;i++)
	{
		if(w[i].pos!=w[cnt-i+1].pos)
		{
			int p1,p2;
			for(int j=1;j<=cnt;j++)
			  if(j!=cnt-i+1&&w[j].pos==w[cnt-i+1].pos)
			    {
			    	p1=j;
			    	break;
				}
			w[p1].pos=w[i].pos;
			w[i].pos=w[cnt-i+1].pos;
			sum++;
		}
	}
	cout<<"\n"<<sum;
	return 0;
}