程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 3270 Cow Sorting(置換循環節)

POJ 3270 Cow Sorting(置換循環節)

編輯:C++入門知識

題目:有一串數字,要將它排列成升序,每次可以交換兩個數,交換一次的代價為兩數之和。要求代價最小。
http://poj.org/problem?id=3270
經典的置換題目,黑書中有詳細介紹。
將原有數列排序之後,得到目標串,這樣就與原串形成了置換。
這樣的置換中分為多個循環,最優解當然是在循環內部進行交換,而循環間的交換只會增加代價。而在一個循環內部的最優解又是用循環中最小的數,依次與其它數進行交換,如果循環節長度為m,那麼最小的數需要交換m-1次,而其它數各一次。
但是這樣並不一定最優,因為有一種特殊情況,就是用循環外的一個數,與循環內的所有數交換,利用這個非常小的數進行中介。
那麼最終就是有兩種情況。一種是用循環內部最小的數為中介,另外一種就是用整個的最小的數為中介交換。
找到每個循環節的長度以及最小元素。
[cpp] 
#include<iostream> 
#include<cstring> 
#include<queue> 
#include<cstdio> 
#include<cmath> 
#include<algorithm> 
#define N 100005 
#define inf 1<<29 
#define MOD 2007 
#define LL long long 
using namespace std; 
struct Node{ 
    int val;//循環中的最小值 
    int cnt;//循環節長度 
}a[N]; 
int n,m[N],tot,t[N]; 
bool flag[N]; 
void dfs(int u){ 
    for(int i=0;i<n;i++){ 
        if(t[i]==u&&!flag[i]){ 
            flag[i]=true; 
            a[tot].cnt++; 
            a[tot].val=min(a[tot].val,t[i]); 
            dfs(m[i]); 
        } 
    } 

int main(){ 
    while(scanf("%d",&n)!=EOF){ 
        int sum=0,mmin=1<<30; 
        for(int i=0;i<n;i++){ 
            scanf("%d",&m[i]); 
            sum+=m[i]; 
            t[i]=m[i]; 
            mmin=min(mmin,m[i]); 
        } 
        sort(m,m+n); 
        tot=0; 
        for(int i=0;i<n;i++){ 
            if(flag[i])  continue; 
            a[tot].val=t[i]; 
            a[tot].cnt=1; 
            flag[i]=true; 
            dfs(m[i]); 
            tot++; 
        } 
        for(int i=0;i<tot;i++) 
            sum+=min(a[i].val*(a[i].cnt-2),mmin*(a[i].cnt+1)+a[i].val); 
        printf("%d\n",sum); 
    } 
    return 0; 
 

作者:ACM_cxlove

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved