国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

POJ - 2299 Ultra-QuickSort解題報(bào)告

2019-11-08 03:25:03
字體:
供稿:網(wǎng)友
題目大意:給你一串?dāng)?shù)(500,000),問你給他們按大小排序至少需要調(diào)換幾次(只能相鄰的調(diào)換)。思路:下面引入概念:對(duì)于一組數(shù)n,有n*(n-1)/2對(duì)組合,現(xiàn)在,定義如果a[i]>a[j]&&i<j,那么數(shù)a[i]和a[j]的位置相反。現(xiàn)在設(shè)這一組數(shù)中,有s對(duì)數(shù)的位置相反了。那么s=b[1]+b[2]+...+b[n](b[i]表示a[i]前面有b[i]個(gè)數(shù)和他的位置相反了)。現(xiàn)在證明:要想使數(shù)組a[]變成從小到大排列,那么至少需要調(diào)換s次相鄰的數(shù),并且只需要調(diào)換s次,就能成功。1.對(duì)于a[i]>a[i+1],那么我只要調(diào)換a[i]和a[i+1],b[]數(shù)組值改變的只有b[i+1]--;即s--;也就是說,s的值只有進(jìn)行一次合適的調(diào)換之后,才能減少一個(gè),不可能通過一次調(diào)換減少2個(gè)及以上。由此得知,至少要調(diào)換s次相鄰的數(shù),s的值才能變成0,此時(shí)才可能是從小到大的順序。另外也可以換一種想法理解這個(gè)事,現(xiàn)在我假設(shè)存在一串從小到大的數(shù)列,那么我顯然可以通過調(diào)換若干次相鄰兩個(gè)數(shù)的位置,使其變成任意順序的數(shù)列,那么,在這個(gè)過程中,每次調(diào)換a[i]和a[i+1]只會(huì)使得b[i+1]++,即s++;(當(dāng)然這還是最理想的狀況,有可能調(diào)換之后s--也說不定。) 我現(xiàn)在尋求的是,通過最少的調(diào)換次數(shù)使得s最快的增加的方法,那么,也只可能是一次調(diào)換,s增加1。這也就是說,我不可能通過少于s次的相鄰數(shù)調(diào)換,使得一個(gè)從小到大的數(shù)列,變成逆序?qū)?shù)的和為s的數(shù)列。那我至少也要把這s次調(diào)換倒著做一遍,才可以把任意序列的數(shù)組變成標(biāo)準(zhǔn)順序。2.假設(shè)任意相鄰的兩個(gè)數(shù)調(diào)換都不能使s變小,那么一定是對(duì)于任意的i,都有a[i]>=a[i+1]。這也就是說,a[]數(shù)組已經(jīng)排序完成。所以,得證,不可能出現(xiàn)數(shù)組還沒有排序好卻所有的相鄰的數(shù)交換都不能使s減少的情況這也就說明了,s次調(diào)換每一次都可以使得s--,即s次調(diào)換一定可以恢復(fù)標(biāo)準(zhǔn)順序。綜上,問題就變成了求一串?dāng)?shù)的逆序和(記從小到大為標(biāo)準(zhǔn)序)關(guān)于時(shí)間復(fù)雜度的分析:要是求出每個(gè)數(shù)a[i]的b[i],那么,那么,那么,一般的思路就是對(duì)于每個(gè)數(shù),查找他前面的數(shù)有多少個(gè)比他小的。然后記錄在b[]數(shù)組中,但是這樣保守估計(jì)500,000*(500,000-1)/2肯定是超時(shí)了。一般數(shù)據(jù)規(guī)模500,000的話,應(yīng)該就是O(n)的復(fù)雜度了,況且這道題還是多組數(shù)據(jù)輸入。O(nlogn)也可以接受。關(guān)于樹狀數(shù)組:這個(gè)樹狀數(shù)組求逆序?qū)?shù)看了好半天才看明白。

首先先說一下什么是樹狀數(shù)組吧,我理解的應(yīng)該就是線段樹的變形(也可能線段樹是樹狀數(shù)組的變形,只不過我先知道的線段數(shù))。其實(shí)大概就是把數(shù)合組,首先兩個(gè)合成一組。然后再四個(gè)合成一大組,八個(gè)合成更大一組,以此類推。然后合成的組可以代替該組的最大標(biāo)號(hào)數(shù)據(jù)。如圖:

然后就是用樹狀數(shù)組求逆序?qū)?shù)了,首先先是建好空的如上圖的樹狀數(shù)組(c數(shù)組的值都為0,但是樹狀數(shù)組的大小已經(jīng)知道了)。然后一個(gè)一個(gè)的按照順序添加數(shù)(加入j就是把a(bǔ)[j]賦值成1),在這個(gè)過程中,每一個(gè)瞬間c[i]都表示當(dāng)前時(shí)刻i組(以第i號(hào)數(shù)為尾的最大組)有多少個(gè)數(shù)在數(shù)組里了。每添加一個(gè)a[i],都會(huì)改變?nèi)舾蓚€(gè)c[]數(shù)組的值,同時(shí)可以確定s[i](該數(shù)組在數(shù)i前面有多少個(gè)比i還小的數(shù)),確定方法,比如:s[6]=c[6]+c[4];s[8]=c[7]+c[6]+c[4];此時(shí)也就確定了該數(shù)組在第j個(gè)數(shù)i之前有多少個(gè)比它大的數(shù)j-s[i]。

總結(jié):這么存這個(gè)數(shù)的好處就是,有規(guī)律的把一串?dāng)?shù)分成幾個(gè)合適大小的組,這樣既不會(huì)使得層數(shù)太高(比如c[i]表示前i個(gè)數(shù)怎么怎么樣就是太高了),也可以很方便的訪問幾個(gè)連續(xù)的數(shù)的總結(jié)果。

 

另外關(guān)于離散化(我覺得就是把一堆數(shù)密集化啊@_@)的問題,我覺得還是用結(jié)構(gòu)體比較方便啊~

 

關(guān)于為什么要是歸并排序而不是冒泡排序:

冒泡排序超時(shí)啊,這不是廢話嗎,但是,假如不超時(shí),那么,冒泡排序過程中調(diào)換的次數(shù)是不是就是最少的相鄰調(diào)換次數(shù)。每次調(diào)換都可以使s--,顯然得出的次數(shù)就是逆序?qū)?shù)。那為什么冒泡排序比歸并排序慢呢,簡單一想,肯定是因?yàn)樽隽颂嗟牟⒉恍枰粨Q位置的判斷。

#include<iostream>#include<stdio.h>#include<algorithm>#include<string.h>#define N 500000+500using namespace std;int n;int b[N]={0};//離散化之后的數(shù) bool a[N]={0};//標(biāo)記數(shù)i是否已經(jīng)在數(shù)組里面了 int c[N]={0};//樹狀數(shù)組的那個(gè)值唄~ int s[N]={0};//數(shù)i前面有s[i]個(gè)數(shù)比它大//int m[N]={0};//數(shù)i前面有m[i]個(gè)數(shù)比它小 struct shu{	int v;	int ord;}d[N]={0};bool cmp1(shu a,shu b){	if(a.v<b.v)return 1;	else return 0;}void init()//預(yù)處理,輸入并離散化處理 {	for(int i=1;i<=n;i++)//輸入n個(gè)數(shù)(1-n) 	{		scanf("%d",&d[i].v);		d[i].ord=i;	}	sort(d+1,d+n+1,cmp1);	for(int i=1;i<=n;i++)	{		b[d[i].ord]=i;	}}void ceshi1(){	for(int i=1;i<=n;i++)	{		cout<<b[i]<<" ";	}	cout<<endl;}void add(int x)//把x加入到數(shù)狀數(shù)組中 {	a[x]=1;	int t=x;	while(t<=n)	{		c[t]++;		t+=(t&(-t));	}}int out(int x)//把數(shù)x之前(包括x)的所有a都加在一起(即合適的c加到一起) {	int s=0;	while(x>0)	{		s+=c[x];		x=x-(x&(-x));	}		return s;}void sol(){	for(int i=1;i<=n;i++)	{		add(b[i]);//把b數(shù)組第i個(gè)數(shù)加入到數(shù)組中		s[i]=i-out(b[i]);	}}int main(){	while(cin>>n)	{		if(n==0)break;		memset(a,0,sizeof(a));		memset(c,0,sizeof(c));		init();		//ceshi1();		long long int sum=0;		sol();		for(int i=1;i<=n;i++)		{			sum+=s[i];		}		PRintf("%lld/n",sum);	}}

注:最后關(guān)于樹狀數(shù)組訪問時(shí)和插入一個(gè)數(shù)據(jù)后,如何尋找需要的節(jié)點(diǎn)的問題,會(huì)找時(shí)間證明。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 成武县| 南雄市| 霍林郭勒市| 梨树县| 桃园市| 百色市| 永吉县| 中山市| 外汇| 城固县| 焉耆| 宝鸡市| 望城县| 九寨沟县| 深水埗区| 万荣县| 驻马店市| 黄石市| 河东区| 桦甸市| 泾阳县| 卓资县| 噶尔县| 遂宁市| 武乡县| 贵定县| 顺义区| 馆陶县| 东至县| 道孚县| 白山市| 西乌珠穆沁旗| 湖南省| 江北区| 卢湾区| 东乌珠穆沁旗| 孝昌县| 灵寿县| 莲花县| 哈巴河县| 象州县|