申請SAE

如果您發現本博客的外觀很難看,那是因為部分外觀文件被中國.國家.防火.牆屏.蔽所致!
請翻~牆!

我的Wordpress博客的地址: http://zhuyf.tk/
顯示具有 圖論 標籤的文章。 顯示所有文章
顯示具有 圖論 標籤的文章。 顯示所有文章

2012年3月16日 星期五

Dijkstra with STL priority_queue 優先隊列

Dijkstra算法是一個經典的求單源最短路的算法,經過堆優化的Dijkstra算法有着良好的性能,雖然Heap的代碼複雜度並不算很高,但是至少也會爲程序的調試帶來一些麻煩。現在C++ STL開放了,所以可以用STL中的PQ容器(優先級隊列)來實現堆。

例題:
【題目描述】
在某個遙遠的國家裏,有n個城市。編號爲1,2,3,……,n。
這個國家的政府修建了m條雙向的公路。每條公路連接着兩個城市。沿着某條公路,開車從一個城市到另一個城市,需要花費一定的汽油。
開車每經過一個城市,都會被收取一定的費用(包括起點和終點城市)。所有的收費站都在城市中,在城市間的公路上沒有任何的收費站。
小紅現在要開車從城市u到城市v(1<=u,v<=n)。她的車最多可以裝下s升的汽油。在出發的時候,車的油箱是滿的,並且她在路上不想加油。
在路上,每經過一個城市,她要交一定的費用。如果她某次交的費用比較多,她的心情就會變得很糟。所以她想知道,在她能到達目的地的前提下,她交的費用中最多的一次最少是多少。這個問題對於她來說太難了,於是她找到了聰明的你,你能幫幫她嗎?
【輸入格式】
第一行5個正整數,n,m,u,v,s。分別表示有n個城市,m條公路,從城市u到城市v,車的油箱的容量爲s升。
接下來有n行,每行1個正整數,fi。表示經過城市i,需要交費fi元。
再接下來有m行,每行3個正整數,ai,bi,ci(1<=ai,bi<=n)。表示城市ai和城市bi之間有一條公路,如果從城市ai到城市bi,或者從城市bi到城市ai,需要用ci升汽油。
【輸出格式】
僅一個整數,表示小紅交費最多的一次的最小值。
如果她無法到達城市v,輸出-1。
【輸入樣例1】
4 4 2 3 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
【輸出樣例1】
8
【輸入樣例2】
4 4 2 3 3
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
【輸出樣例2】
-1
【數據規模】
對於60%的數據,滿足n<=200,m<=10000,s<=200
對於100%的數據,滿足n<=10000,m<=50000,s<=1000000000
對於100%的數據,滿足ci<=1000000000,fi<=1000000000,可能有兩條邊連接着相同的城市。

[分析]
這道題是道判定類題目,算法是二分答案+單源最短路。
由於數據很大,二分N+SPFA會超時1組,所以考慮Dijkstra+Heap。
[我的代碼]

C++语言: Codee#25838
001 /*
002 *Problem: NOIP模擬題 收費站
003 *Author: YeefanZhu
004 *Website: www.yeefanblog.tk
005 *GTalk: zyfworks@gmail.com
006 */
007 #include <cstdio>
008 #include <vector>
009 #include <cstdlib>
010 #include <algorithm>
011 #include <queue>
012 using namespace std;
013 const int MAXN=10001;
014 const int INF=1100000000;
015 int Cost[MAXN],BS[MAXN];
016 int N,M,S,B,E;
017 vector<int> Map[MAXN];
018 vector<int>Val[MAXN];
019
020 inline void init()
021 {
022     scanf("%d %d %d %d %d\n",&N,&M,&B,&E,&S);
023     for(int i=1;i<=N;i++)
024     {
025         scanf("%d\n",&Cost[i]);
026         BS[i]=Cost[i];
027     }
028     sort(BS+1,BS+N+1);
029     int a,b,v;
030     for(int i=1;i<=M;i++)
031     {
032         scanf("%d %d %d\n",&a,&b,&v);
033         Map[a].push_back(b);
034         Map[b].push_back(a);
035         Val[a].push_back(v);
036         Val[b].push_back(v);
037     }
038 }
039
040 priority_queue<pair<int,int> > PQ;
041 int Used[MAXN];
042 int Dist[MAXN];
043
044 inline bool SP(int x)
045
046 {
047     if(Cost[B]>x) return false;
048     for(int i=1;i<=N;i++) {Used[i]=0,Dist[i]=INF;}
049     Dist[B]=0;
050     PQ.push(make_pair(0,B));
051     int u,v,cost;
052     while(!PQ.empty())
053     {
054         u=PQ.top().second;
055         PQ.pop();
056         if(!Used[u])
057         {
058             Used[u]=1;
059             for(unsigned int i=0;i<Map[u].size();i++)
060             {
061                 v=Map[u][i];
062                 cost=Val[u][i];
063                 if(Cost[v]>x) continue;
064                 if(!Used[v]&&Dist[v]-Dist[u]>cost)
065                 {
066                     Dist[v]=Dist[u]+cost;
067                     PQ.push(make_pair(-Dist[v],v));
068                 }
069             }
070         }
071     }
072     if(Dist[E]>S) return false;
073     return true;
074 }
075
076 inline void solve()
077 {
078     int L=1,R=N;
079     int Mid;
080     if(!SP(BS[N])) {printf("-1\n");return;}
081     int Ans;
082     bool flag;
083     while(L<=R)
084     {
085         Mid=(L+R)>>1;
086         flag=SP(BS[Mid]);
087         if(flag)
088         {
089             Ans=BS[Mid];
090             R=Mid-1;
091         }
092         else L=Mid+1;
093     }
094     printf("%d\n",Ans);
095 }
096
097 int main()
098 {
099     freopen("cost.in","r",stdin);
100     freopen("cost.out","w",stdout);
101     init();
102     solve();
103     return 0;
104 }

2012年3月6日 星期二

【轉載】淺談2—SAT問題

2-SAT:http://www.cppblog.com/ACflying/archive/2009/06/06/86912.html
1 2 - SAT就是2判定性問題,是一種特殊的邏輯判定問題。
2 2 - SAT問題有何特殊性?該如何求解?
3 我們從一道例題來認識2 - SAT問題,並提出對一類2 - SAT問題通用的解法。 
Poi  0106  Peaceful Commission [和平委員會]:

某國有n個黨派,每個黨派在議會中恰有2個代表。
現在要成立和平委員會 ,該會滿足:
每個黨派在和平委員會中有且只有一個代表
如果某兩個代表不和,則他們不能都屬於委員會
代表的編號從1到2n,編號為2a
- 1 、2a的代表屬於第a個黨派
輸入n(黨派數),m(不友好對數)及m對兩兩不和的代表編號
其中1≤n≤
8000 0 ≤m ≤ 20000
 

求和平委員會是否能創立。若能,求一種構成方式。
輸入:     輸出:
3   2         1       1   3         4         2   4         5               
原題可描述為:

有n個組,第i個組裡有兩個節點Ai, Ai
'  。需要從每個組中選出一個。而某些點不可以同時選出(稱之為不相容)。任務是保證選出的n個點都能兩兩相容。
(在這裡把Ai, Ai
'  的定義稍稍放寬一些,它們同時表示屬於同一個組的兩個節點。也就是說,如果我們描述Ai,那麼描述這個組的另一個節點就可以用Ai '
初步構圖
如果Ai與Aj不相容,那麼如果選擇了Ai,必須選擇Aj‘ ;同樣,如果選擇了Aj,就必須選擇Ai’ 。   Ai             Aj
' 
 Aj             Ai‘                    
這樣的兩條邊對稱


我們從一個例子來看:
假設4個組,不和的代表為:1和4,2和3,7和3,那麼構圖:
假設:首先選1 3必須選,2不可選 8必須選,
4 、7不可選  5 、6可以任選一個
矛盾的情況為:
存在Ai,使得Ai既必須被選又不可選。

得到演算法1:

枚舉每一對尚未確定的Ai, Ai‘ ,任選1個,推導出相關的組,若不矛盾,則可選擇;否則選另1個,同樣推導。若矛盾,問題必定無解。
此演算法正確性簡要說明:
由於Ai,Ai
'  都是尚未確定的,它們不與之前的組相關聯,前面的選擇不會影響Ai, Ai '  。
演算法的時間複雜度在最壞的情況下為O(nm)。
在這個演算法中,並沒有很好的利用圖中邊的對稱性
 更一般的說:
在每個一個環裡,任意一個點的選擇代表將要選擇此環裡的每一個點。不妨把環收縮成一個子節點(規定這樣的環是極大強連通子圖)。新節點的選擇表示選擇這個節點所對應的環中的每一個節點.對於原圖中的每條邊Ai
-> Aj(設Ai屬於環Si,Aj屬於環Sj)如果Si≠Sj,則在新圖中連邊:Si -> Sj

這樣構造出一個新的有向無環圖。此圖與原圖等價。
通過求強連通分量,可以把圖轉換成新的有向無環圖,在這個基礎上,介紹一個新的演算法。

新演算法中,如果存在一對Ai, Ai
' 屬於同一個環,則判無解,否則將採用拓撲排序,以自底向上的順序進行推導,一定能找到可行解。

至於這個演算法的得來及正確性,將在下一段文字中進行詳細分析。
回憶構圖的過程:
對於兩個不相容的點 Ai, Aj,構圖方式為:Ai
-> Aj ' ,Aj->Ai ' ,前面提到過,這樣的兩條邊對稱,也就是說:
如果存在Ai
-> Aj,必定存在Aj ' ->Ai '
等價於:Ai -> Ak,Ak ' ->Ai '  方便起見,之後“ -> ”代表這樣一種傳遞關係.



猜測1:圖中的環分別對稱
如果存在Ai,Aj,Ai,Aj屬於同一個環(記作Si),那麼Ai
' , Aj ' 也必定屬於一個環(記作Si ' ).
再根據前面的引理,不難推斷出每個環分別對稱。

證明方式與引理相類似
一個稍稍複雜點的結構,其中紅、藍色部分分別為兩組對稱的鏈結構
推廣2:對於任意一對Si, Si
'  ,Si的後代節點與Si '  的前代節點相互對稱。
繼而提出:
猜測2:若問題無解,則必然存在Ai, Ai
'  ,使得Ai,Ai ' 屬於同一個環。也就是,如果每一對Ai,Ai '  都不屬於同一個環,問題必定有解。下面給出簡略證明:
先提出一個跟演算法1相似的步驟:
如果選擇Si,那麼對於所有Si
-> Sj,Sj都必須被選擇。
而Si
'  必定不可選,這樣Si’的所有前代節點也必定不可選(將這一過程稱之為刪除)。
由推廣2可以得到,這樣的刪除不會導致矛盾。

假設選擇S3
'  
?選擇S3 ' 的後代節點, S1 '
?刪除S3
?刪除S3的前代節點S1
S1與S1
' 是對稱的

每次找到一個未被確定的Si,使得不存在Si
-> Si '  選擇Si及其後代節點而刪除Si’及Si‘的前代節點。一定可以構造出一組可行解。
因此猜測2成立。

另外,若每次盲目的去找一個未被確定的Si,時間複雜度相當高。
以自底向上的順序進行選擇、刪除,這樣還可以免去“選擇Si的後代節點”這一步。
用拓撲排序實現自底向上的順序。

一組可能的拓撲序列(自底向上):S1
' ,S2,S2 ' ,S3 ' ,S3,S1

演算法2的流程:
1 .構圖 2 .求圖的極大強連通子圖 3 .把每個子圖收縮成單個節點,根據原圖關係構造一個有向無環圖 4 .判斷是否有解,無解則輸出(退出) 5 .對新圖進行拓撲排序 6 .自底向上進行選擇、刪除 7 .輸出

小結:
整個演算法的時間複雜度大概是O(m),解決此問題可以說是相當有效了。
在整個演算法的構造、證明中反覆提到了一個詞:對稱。發現、利用了這個圖的特殊性質,我們才能夠很好的解決問題。
並且,由2
- SAT問題模型變換出的類似的題目都可以用上述方法解決。

全文總結:
充分挖掘圖的性質,能夠更好的解決問題。
不僅僅是對於圖論,這種思想可以在很多問題中得到很好的應用。
希望我們能掌握此種解題的思想,在熟練基礎演算法的同時深入分析、靈活運用、大膽創新,從而解決更多更新的難題。

2012年2月27日 星期一

圖論練習題 備用交換機 gd 題解

問題描述
n個城市之間有通訊網絡,每個城市都有通訊交換機,直接或間接與其它城市連接。因電子設備容易損壞,需給通訊點配備備用交換機。但備用交換機數量有限,不能全部配備,只能給部分重要城市配置。於是規定:如果某個城市由於交換機損壞,不僅本城市通訊中斷,還造成其它城市通訊中斷,則配備備用交換機。請你根據城市線路情況,計算需配備備用交換機的城市個數,及需配備備用交換機城市的編號。
【輸入格式】
輸入文件有若干行
第一行,一個整數n,表示共有n個城市(2<=n<=100)
下面有若干行,每行2個數a、b,a、b是城市編號,表示a與b之間有直接通訊線路。
【輸出格式】
輸出文件有若干行
第一行,1個整數m,表示需m個備用交換機,下面有m行,每行有一個整數,表示需配備交換機的城市編號,輸出順序按編號由小到大。如果沒有城市需配備備用交換機則輸出0。

圖論練習題 圖的平方 ljb

【問題描述】
有向圖G=(V,E)的平方是圖G^2=(V,E^2),該圖滿足下列條件:(u,w)∈E^2當且僅當對v∈V,有(u, v)∈E,且(v,w)∈E。亦即,如果圖G中頂點u和w之間存在著一條恰包含兩條邊的路徑時,則G^2必包含該邊(u,w)。
請編程序對於給定的有向圖G,查詢邊(u,w)是否存在於平方圖G^2中。
【輸入文件】
第一行有兩個整數,v(1<=v<=100000),m(1<=m<=1000),其中v表示圖G的頂點個數,(頂點按1~v編號);
接下來有m行,每行包含4個整數u1,u2,v1,v2,表示在圖G中,頂點區間[u1,u2]中的每一個頂點至頂點區間[v1,v2]中的每一個頂點都有邊相連;
接下來有一行,一個整數n(1<=n<=1000),表示查詢的個數;
接下來有n行,每一行有4個整數,x1,x2,y1,y2,表示一個詢問,即詢問在平方圖G^2中,其頂點區間[x1,x2]中的每一個頂點至頂點區間[y1,y2]中的每一個頂點是否都有邊。

圖論練習題 摔跤 rassle 題解

【問題描述】
有兩種類型的職業摔跤手:一種是“好選手”,另一種是“差選手”。對於任何一對職業摔跤手來說,他們中可能有、也可能沒有比賽。假定有 n 位職業摔跤手,並且有一份清單,上面列出了 r 對參加比賽的摔跤手。寫一個程序,它能夠確定是否可能指定某些摔跤手為好選手,而將餘下的摔跤手指定為壞選手,從而使得每一場比賽都是在一個好選手與一個差選手之間進行。如果有可能做出這樣的指定,你的程序就應該將它產生出來,否則輸出無解“No”。
【輸入格式】
第1行有三個整數n,r。n是職業摔跤手的數量,r是比賽場數,它們之間用一個空格隔開。
接下來的r行,每行用兩個數V1,V2表示V1號摔跤手與V2號摔跤手比賽,選手從1開始編號。
【輸出格式】
輸出有兩行,第一行“好選手”的編號,第二行為“差選手”的編號,編號之間用一個空格隔開。
注意:為了鼓勵選手,使輸出答案唯一,請儘量多的將選手設為“好選手”,並且在可行條件下選擇編號小的選手為“好選手”。
如果無解,則輸出一行“No”。

【拓撲排序練習題】課程安排問題 curriculum

【問題描述】
一個軟體專業的學生必須學習一系列基本課程,其中有些課程是基礎課,它獨立於其它課程,如《高等數學》、《計算引論》;而另一些課程必須在學完作為它的基礎的先修課程才能開始。如,在《程序設計基礎》和《離散數學》學完之前就不能開始學習《資料結構》。這些先決條件定義了課程之間的領先(優先)關係。請你在符合上述領先(優先)條件的前提下,給出所有課程的一個有序序列,以方便學校排課。
【輸入格式】
輸入文件有若干行
第一行,一個整數n,表示共有n(0<n<=100)門課程
第2--n+1行分別表示第1--n門課程的先修課程資訊,每行有若干個整數m,s1,s2,...,sm
m表示該門課程有m門先修課程,s1,s2,...,sm分別表示m門先修課的編號,如果該門課沒有先修課程,則m為0。
【輸出格式】
一行,n個整數,表示n門課程編號的有序序列(如果這樣的序列不存在,則輸出no;如果有多個這樣的序列,輸出字典序最小的)

【強連通分量】四面楚歌 virus 解題報告

【題目描述】
公元2008年10月31日星期五,篤志者所在的整個機房由於猖獗的病毒一片恐慌。經查證,病毒是由A1機器散播開來的。。這要追溯到29日,篤志者由於病毒被迫從A1機器撤離。
一想到病毒是從自己的機器傳開的,篤志者就心神不寧。他決定搞清楚病毒是怎麼散播開來的。事實上,機房內的機器並不是全部都能夠互相感染的。篤志者(ceeji)好不容易經過測試得到了機房中各機器間是否連通的圖表,就在他馬上就要得出結果的時候,大腦突然亂了!問題的嚴重性在於:如果他不在1s內搞清楚這個問題,機房就會整體癱瘓。現在篤志者求助於你,他需要知道病毒從未感染機房開始,最少入侵幾臺機器之後,機房就會整體感染。
【輸入格式】
文件的第一行為一個整數n,第二行至第n+1行為n*n的矩陣(若第i行第j列為1,則機器i能對機器j進行ARP攻擊(即感染機器j),若第i行第j列為0,則機器i不能感染機器j)。
文件名為“2.in”。
【輸出格式】
輸出文件只有一行,為篤志者想知道的最少感染機器數。
文件名為“2.out”。

2012年2月16日 星期四

[多源最短路]USACO 奶牛聚會 spart

譯: zqzas
N(1 ≤ N ≤ 1000)個農場中的每個農場都有一隻奶牛去參加位於第X個農場的聚會.共有M (1 ≤ M ≤ 100,000)條單向的道路,每條道路連接一對農場.通過道路i會花費Ti (1 ≤ Ti ≤ 100)的時間.
作爲參加聚會的奶牛必須走到聚會的所在地(農場X).當聚會結束時,還要返回各自的農場.奶牛都是很懶的,她們想找出花費時間最少的路線.由於道路都是單向的,所有她們前往農場X的路線可能會不同於返程的路線.
Of all the cows, what is the longest amount of time a cow must spend walking to the party and back? 對於所有參加聚會的奶牛,找出前往聚會和返程花費總時間最多的奶牛,輸出這隻奶牛花費的總時間.

2012年2月12日 星期日

[次短路徑]HAOI2005 路由選擇問題 route 解題報告

路由選擇問題

【問題描述】

    X城有一個含有N個節點的通信網絡,在通信中,我們往往關心資訊從一個節點I傳輸到節點J的最短路徑。遺憾的是,由於種種原因,線路中總有一些節點會出故障,因此在傳輸中要避開故障節點。
任務一:在己知故障節點的情況下,求避開這些故障節點,從節點I到節點J的最短路徑S0。
任務二:在不考慮故障節點的情況下,求從節點I到節點J的最短路徑S1、第二最短路徑S2。

【輸入文件】

第1行: N I J (節點個數 起始節點 目標節點)
第2—N+1行: Sk1 Sk2…SkN (節點K到節點J的距離爲SkJ K=1,2,……,N)
最後一行: P T1 T2……Tp (故障節點的個數及編號)

【輸出文件】

S0 S1 S2 (S1<=S2 從節點I到節點J至少有兩條不同路徑)

2012年2月5日 星期日

USACO 2009 9th 熱浪 heatwv 解題報告

USACO/heatwv

第九題: 熱浪 [300分] [Rob Kolstad (傳統題目), 2009]
德克薩斯純樸的民眾們這個夏天正在遭受巨大的熱浪!!!他們的德克薩斯長角牛吃起來不錯, 可是他們並不是很擅長生產富含奶油的乳製品。Farmer John此時以先天下之憂而憂,後天下 之樂而樂的精神,身先士卒地承擔起向德克薩斯運送大量的營養冰涼的牛奶的重任,以減輕德 克薩斯人忍受酷暑的痛苦。
FJ已經研究過可以把牛奶從威斯康星運送到德克薩斯州的路線。這些路線包括起始點和終點先 一共經過T (1 <= T <= 2,500)個城鎮,方便地標號為1到T。除了起點和終點外地每個城鎮 由兩條雙向道路連向至少兩個其它地城鎮。每條道路有一個通過費用(包括油費,過路費等等)。 考慮這個有7個城鎮的地圖。城鎮5是奶源,城鎮4是終點(括號內的數字是道路的通過費用)。

2012年2月4日 星期六

【搜索】單詞遊戲 words 解題報告

Title: 單詞遊戲
Input: words.in
Output: words.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★☆
【問題描述】
慧慧和南南在玩一個單詞遊戲。
他們輪流說出一個僅包含母音字母的單詞,並且後一個單詞的第一個字母必須與前一個單詞的最後一個字母一致。
遊戲可以從任何一個單詞開始。
任何單詞禁止說兩遍,遊戲中只能使用給定詞典中含有的單詞。
遊戲的複雜度定義為遊戲中所使用的單詞長度總和。
編寫程序,求出使用一本給定的詞典來玩這個遊戲所能達到的遊戲最大可能複雜度。

2012年1月31日 星期二

[歐拉路]NOIP模擬題:傳送機 sent 解題報告

  【題目描述】
  刷完牙洗完臉,黃黃同學就要上課去了。可是黃黃同學每次去上課時總喜歡把校園裡面的每條路都走一遍,當然,黃黃同學想每條路也只走一遍。我們一般人很可能對一些地圖是辦不到每條路走一遍且僅走一遍的,但是黃黃同學有個傳送機,他可以任意地將一個人從一個路口傳送到任意一個路口。
可是,每傳送一次是需要耗費巨大的內力的,黃黃同學希望可以用最少的傳送次數完成遊遍校園,你能幫助他嗎 ?
因為黃黃同學只是遊歷校園,於是我們可以認為黃黃同學可以從任意點開始,到任意點結束。


2012年1月30日 星期一

NOI2007 社交網絡 network 解題報告

【題目描述】 
 懶得貼上試題了~發個連結:NOI2007 Day1試題連結
 【分析】
這是這幾年NOI中最簡單的題了~就是一個多源最短路+乘法原理。 

用Map[i][j]表示i、j之間的最短路徑長度; 
用Path[i][j]表示i、j之間最短路徑的條數(初始化為1)。

 先用Floyd算法求每兩點之間的最短路,鬆弛時要注意,如果出現:
 Map[i][k]+Map[k][j]==Map[i][j] 則說明這又是最短路,所以Path[i][j]+=Path[i][k]*Path[k][j]。
 如果可以鬆弛,即Map[i][k]+Map[k][j]<Map[i][j],則Path[i][j]=Path[i][k]*Path[k][j]即可。

 最後亂搞一個三重循環求I(v),按照題意走即可AC。

2012年1月28日 星期六

[最短路徑][二分答案]USACO Jan08 Silver 架設電話線 phoneline 解題報告

Title: 架設電話線【試題傳送門
Input: phoneline.in
Output: phoneline.out
Time Limit: 1000 ms
Memory Limit: 16 MB
Level: ★★☆
Farmer John打算將電話線引到自己的農場,但電信公司並不打算為他提供免費服務。於是,FJ必須為此向電信公司支付一定的費用。
FJ的農場周圍分佈著N(1 <= N <= 1,000)根按1..N順次編號的廢棄的電話線杆,任意兩根電話線杆間都沒有電話線相連。一共P(1 <= P <= 10,000)對電話線杆間可以拉電話線,其餘的那些由於隔得太遠而無法被連接。
第i對電話線杆的兩個端點分別為A_i、B_i,它們間的距離為L_i (1 <= L_i <= 1,000,000)。資料中保證每對{A_i,B_i}最多隻出現1次。編號為1的電話線杆已經接入了全國的電話網絡,整個農場的電話線全都連到了編號 為N的電話線杆上。也就是說,FJ的任務僅僅是找一條將1號和N號電話線杆連起來的路徑,其餘的電話線杆並不一定要連入電話網絡。
經過談判,電信公司最終同意免費為FJ連結K(0 <= K < N)對由FJ指定的電話線杆。對於此外的那些電話線,FJ需要為它們付的費用,等於其中最長的電話線的長度(每根電話線僅連結一對電話線杆)。如果需要連 結的電話線杆不超過K對,那麼FJ的總支出為0。
請你計算一下,FJ最少需要在電話線上花多少錢。
程序名: phoneline

2012年1月25日 星期三

GZOI2011 Rail 解題報告

第四題(40分)
提交文件:Rail.exe
輸入文件:Rail.in
輸出文件:Rail.out
題目描述:
你所在的省剛獲得國家撥款興建高鐵,高鐵的起止城市是國家選定的,中途可能經過若干城市。根據國家撥款的政策,國家將負擔費用最大的兩個區間,其餘的必須由省負擔。假如高鐵線路中途只經過一個城市,國家只負擔費用較大的區間。假如是直達的,國家將不負擔任何費用。
你被省裡選定作為這個項目的總工程師,你必須規劃出一條高鐵線路,使得省負擔的費用最少。當然,路線上每個城市最多只經過一次。

2012年1月19日 星期四

[轉載]次短路径与次小生成树问题的简单解法

轉載自http://www.byvoid.com/blog/2-sp-mst/ ,轉載請註明!

  次短路径与次小生成树问题的简单解法

 

[次短路径]

次短路径可以看作是k短路径问题的一种特殊情况,求k短路径有Yen算法等较为复杂的方法,对于次短路径,可以有更为简易的方法。下面介绍一种求两个顶点之间次短路径的解法。

2012年1月17日 星期二

[網絡最大流]POI1999 洞穴探險 gro 解題報告

問題描述

古老的Byte山上有一處神祕的連環洞穴。考古學家們爲了對這個洞穴進行研究,組織了一次探險活動。他們花了幾天的時間仔細地翻閱了前人留下的資料,對該連環洞穴有了大致的瞭解。

這是一個有許多不同的小溶洞組成的連環洞穴,每個小溶洞都分佈在不同的地層中,並且可能通過洞穴隧道與其他小溶洞相通。

考古學家們已經發現了作爲連環洞穴的入口的一個小溶洞,並且根據前人的資料,繪製出了洞穴的地圖,標明瞭哪些小溶洞之間是有洞穴隧道相連的。

富有冒險和激情的考古學家們都期望自己能夠獨自進行探險活動。於是,他們又提出了這樣的要求:從入口的溶洞出發時,每個人都選擇一條不同的 洞穴隧道前進;探險結束時,每個人都是通過不同的洞穴隧道抵達最底層的小溶洞。當然了,這些考古學家也達成了妥協:在探險的過程中,可以有不止一名的考古 學家通過同一條洞穴隧道。 爲了體現這次探險活動的一往直前的精神,考古學家們還決定,要從小溶洞入口進入,一直抵達最底層的溶洞!每個考古學家探險路線上通過的小溶洞所在的地層必 須比該路線上前一個溶洞的地層低。

考古學家提出來如此多的要求使得本次探險活動的組織者犯了愁,他究竟最多能邀請多少位考古學家來參加這項活動呢?

2012年1月13日 星期五

[圖論]OI練習題:商人的宣傳 merchant 解題報告

題目連結:http://cogs.yeefanblog.tk/t/441


【問題描述】


Bruce是K國的商人,他在A州成立了自己的公司,這次他的公司生產出了一批性能很好的產品,準備宣傳活動開始後的第L天到達B州進行新品拍賣,期間Bruce打算將產品拿到各個州去做推銷宣傳,以增加其影響力。
K國有很多個州,每個州都與其他一些州相鄰,但是K國對商人作宣傳卻有一些很奇怪的規定:
(1)商人只能從某些州到達另外一些州,即連通路綫是單向的,而且有些州可能是到達不了的。
(2)商人不允許在同一個州連續宣傳兩天或以上,每天宣傳完必須離開該州。
(3)商人可以多次來到同一個州進行宣傳。
Bruce想:“我必須找出一條影響力最大的路綫才行,但首先必須知道到底有多少這種符合規定的宣傳路綫可供我選擇。”現在Bruce把任務交給了你,並且出於考慮以後的需要,你還要幫他算出給出的兩州之間的路綫的總數。
【輸入格式】
輸入格式(輸入文件名merchant.in)
輸入文件第1行包含3個整數n,m,L(1≤n,L≤100),分別表示K國的州數、連通路綫的數量,以及多少天后必須到達B州。
接下來有m行,每行一對整數五),(1≤x,y≤n),表示商人能從x州到達y州。
第m+2行爲一個整數q(1≤q≤100),表示Bruce有q個詢問。
下面q行每行兩個整數A,B(1≤A,B≤n),即A、B州的位置。

【輸出格式】
輸出格式(輸出文件名merchant.out)
輸出文件包含q行,每行一個整數t,爲所求的從A州到B州滿足上述規定的路綫總數。
輸入數據中的詢問將保證答案f在長整數範圍內,即i<2^31。

【輸入輸出樣例】
輸入(merchant.in)
4 5 6
1 2
2 3
3 4
4 1
2 4
2
1 4
4 2
輸出(merchant.out)
2
1

[分析]

這種題型我也不知道怎麽去描述,貌似是圖論中的DP~~我用了Floyd的框架寫的。Floyd算法其實就是動態規劃。因爲需要L天的宣傳,所以需要執行“Floyd 變形算法” L-1次。


我的程序的時間複雜度:O(L*n^3)

[我的代碼]

C++语言: Codee#25159
01 /*
02 *Prob:商人的宣傳(http://cogs.yeefanblog.tk/t/441)
03 *Author:Yee-fan Zhu(http://www.yeefanblog.tk/)
04 */
05 #include <iostream>
06 #include <cstdio>
07 #include <cstdlib>
08 using namespace std;
09
10 const int MAXN=101;
11 int Temp[MAXN][MAXN];
12 int Result[MAXN][MAXN];
13 int Start[MAXN][MAXN];
14
15 int N,M,L;
16
17 void init()
18 {
19     scanf("%d %d %d\n",&N,&M,&L);
20    
21     for (int i=1;i<=N;i++)
22         for (int j=1;j<=N;j++)
23             Temp[i][j]=0,
24             Result[i][j]=0,
25             Start[i][j]=0;
26    
27     for (int i=1;i<=M;i++)
28     {
29         int x,y;
30         scanf("%d %d\n",&x,&y);
31         Start[x][y]++;
32         Result[x][y]++;
33     }
34 }
35
36 void work()
37 {
38     for (int m=1;m<=L-1;m++)
39     {
40         for (int i=1;i<=N;i++)
41             for (int j=1;j<=N;j++)
42                 Temp[i][j]=Result[i][j],Result[i][j]=0;
43        
44         for (int i=1;i<=N;i++)
45             for (int j=1;j<=N;j++)
46                 for (int k=1;k<=N;k++)
47                     Result[i][j]+=Temp[i][k]*Start[k][j];
48     }
49    
50     int Q,x,y;
51     scanf("%d\n",&Q);
52     for(int i=1;i<=Q;i++)
53     {     
54         scanf("%d %d\n",&x,&y);
55         printf("%d\n",Result[x][y]);
56     }
57 }
58
59 int main()
60 {
61     freopen("merchant.in","r",stdin);
62     freopen("merchant.out","w",stdout);
63     init();
64     work();
65     return 0;
66 }

2012年1月3日 星期二

網絡流入門試題 [最大流]運輸問題1 maxflowa

題目連結:http://cogs.yeefanblog.tk/t/11
Title: 运输问题1
Input: maxflowa.in
Output: maxflowa.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★★☆
【问题描述】
    一个工厂每天生产若干商品,需运输到销售部门进行销售。从产地到销地要经过某些城镇,有不同的路线可以行走,每条两城镇间的公路都有一定的流量限制。请你计算,在不考虑其它车辆使用公路的前提下,如何充分利用所有的公路,使产地运输到销地的商品最多,最多能运输多少商品。
【输入格式】
输入文件有若干行
第一行,一个整数n,表示共有n个城市(2<=n<=100)
下面有n行,每行有n个数字。第p行第q列的数字表示城镇p与城镇q之间有无公路连接。数字为0表示无,大于0表示有公路,且该数字表示该公路流量。
【输出格式】
输出文件有一行
第一行,1个整数n,表示最大流量为n。
【输入输出样例】
输入文件名: maxflowa.in
6
0 4 8 0 0 0
0 0 4 4 1 0
0 0 0 2 2 0
0 0 0 0 0 7
0 0 0 6 0 9
0 0 0 0 0 0
输出文件名:maxflowa.out
8

【分析】
基礎的最大流問題。
由於源點沒有入度、匯點沒有出度,所以由樣例可以看出1號的源點,N號是匯點。
剩下就是用Ford-Fulkerson方法求解最大流即可。
《算法導論》上,Ford-Filkerson方法的偽代碼描述是:
FORD_FULKERSON(G,s,t)
1 for each edge(u,v)∈E[G]
2 do f[u,v] <— 0
3 f[v,u] <— 0
4 while there exists a path p from s to t in the residual network Gf
5 do cf(p) <— min{ cf(u,v) : (u,v) is in p }
6 for each edge(u,v) in p
7 do f[u,v] <— f[u,v]+cf(p)
8 f[v,u] <— -f[u,v]
        

【我的代碼】

C++语言: Codee#25004
001 /*
002 *Problem:http://cogs.yeefanblog.tk/t/11
003 *Author:Yee-fan Zhu
004 *Website:http://www.zhuyf.tk/
005 *Method:網絡流 最大流 Full-Fulkerson
006 */
007 #include <iostream>
008 #include <cstdio>
009 #include <cstdlib>
010 #include <cstring>
011 #include <queue>
012 using namespace std;
013
014 const int INF=0x7ffffff;
015 const int MAXN=101;
016 int Map[MAXN][MAXN];
017 int Father[MAXN];
018 bool Used[MAXN];
019 int Ans;
020 int N,M;
021 int S,T;
022
023 void Ford_Fulkerson()
024 {
025     while(1)
026     {
027         queue<int>Q;
028         memset(Used,0,sizeof(Used));
029         memset(Father,0,sizeof(Father));
030
031         int now;
032         Used[S]=true;
033         Q.push(S);
034         while(!Q.empty())
035         {
036             now=Q.front();
037             Q.pop();
038             if(now==T)
039                 break;
040             for (int i=1;i<=N;i++)
041             {
042                 if(Map[now][i] && !Used[i])
043                 {
044                     Father[i]=now;
045                     Used[i]=true;
046                     Q.push(i);
047                 }
048             }
049         }
050
051         if(!Used[T])// There is no Augmenting Path.
052             break;
053
054         int u;
055         int Min=INF;
056         for (u=T;u!=S;u=Father[u])
057         {
058             if(Map[Father[u]][u]<Min)
059                 Min=Map[Father[u]][u];
060         }
061
062         for (u=T;u!=S;u=Father[u])
063         {
064             Map[Father[u]][u]-=Min;
065             Map[u][Father[u]]+=Min;
066         }
067
068         Ans+=Min;
069     }
070 }
071
072 void init()
073 {
074     scanf("%d\n",&N);
075     M=0;
076     memset(Map,0,sizeof(Map));
077
078     int v;
079     for (int i=1;i<=N;i++)
080     {
081         for (int j=1;j<=N;j++)
082         {
083             scanf("%d",&v);
084             Map[i][j]=v;
085             if(v)
086                 M++;
087         }
088     }
089     S=1;
090     T=N;
091     return;
092 }
093
094 int main()
095 {
096     freopen("maxflowa.in","r",stdin);
097     freopen("maxflowa.out","w",stdout);
098     init();
099     Ford_Fulkerson();
100     printf("%d\n",Ans);
101     return 0;
102 }