BSOJ3362 -- 【模擬試題】聰明的農民
阿新 • • 發佈:2019-02-18
計算交換次數時可以用並查集來做,但是也有一個貪心就是直接換,但是無法證明其正確性。
#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; }