4.2 有向圖

4.2.1介紹

在有向圖中,邊是單向的.實(shí)際上組合性的結(jié)構(gòu)對(duì)算法有深遠(yuǎn)影響,使得有向圖和無(wú)向圖之間的處理大有不同.
頂點(diǎn)出度: 由該頂點(diǎn)指出邊的總數(shù).
頂點(diǎn)入度:指向該頂點(diǎn)的邊的總數(shù).
一條有向邊的第一個(gè)頂點(diǎn)叫頭,第二個(gè)頂點(diǎn)稱(chēng)為尾.(v → w)
一幅有向圖的頂點(diǎn)可能存在4種關(guān)系:
1.沒(méi)有邊相連接
2.存在v → w
3.存在w → v
4.存在 雙向 v ? w

4.2.2有向圖的數(shù)據(jù)類(lèi)型Digraph
package algorithm.algorithmbook.graph;
/**
 * description: 有向圖的數(shù)據(jù)接口
 *
 * @author leon
 * @date 18-2-23.
 */
public interface IDigraph {
    /**
     * @return 頂點(diǎn)數(shù)
     */
    int V();
    /**
     * @return 邊數(shù)
     */
    int E();
    /**
     * 添加 v-> w 的邊
     *
     * @param v 起點(diǎn)
     * @param w 終點(diǎn)
     */
    void addEage(int v, int w);
    /**
     * 由v指出所連接的所有頂點(diǎn)
     *
     * @param v 頂點(diǎn)
     * @return 可迭代的頂點(diǎn)列表
     */
    Iterable<Integer> adj(int v);
    /**
     * 這個(gè)方法有時(shí)很有用,返回的是圖的一個(gè)副本,但將其中所有的邊的方向反向.
     * 因?yàn)榭梢哉页?指向"每個(gè)頂點(diǎn)的邊,而adj()為指出每個(gè)頂點(diǎn)的邊.
     * @return 該圖的反向圖
     */
    IDigraph reverse();
    /**
     *
     * @return 字符串描述
     */
    String toString();
}
package algorithm.algorithmbook.graph;
import java.io.DataInputStream;
import algorithm.algorithmbook.graph.IDigraph;
/**
 * description:有向圖
 *
 * @author leon
 * @date 18-2-23.
 */
public class Digraph implements IDigraph {
    //頂點(diǎn)數(shù)
    private final int v;
    //邊數(shù)
    private int e;
    //鄰接表
    private Bag<Integer>[] adj;
    public Digraph(int v) {
        this.v = v;
        this.e = 0;
        adj = (Bag<Integer>[]) new Bag[v];
        for (int i = 0; i < v; i++) {
            adj[i] = new Bag<Integer>();
        }
    }
    public Digraph(DataInputStream input) {
        v = 0;
    }
    @Override
    public int V() {
        return v;
    }
    @Override
    public int E() {
        return e;
    }
    @Override
    public void addEage(int v, int w) {
        //因?yàn)檫@里是有向圖,所以只需要連接 v->w 的邊
        adj[v].add(w);
        e++;
    }
    @Override
    public Iterable<Integer> adj(int v) {
        return adj[v];
    }
    @Override
    public IDigraph reverse() {
        Digraph revDigraph = new Digraph(v);
        for (int i = 0; i < v; i++) {
            for (int to : revDigraph.adj(i)) {
                addEage(to, v);
            }
        }
        return revDigraph;
    }
}
4.2.3 有向圖的可到達(dá)性.

單點(diǎn)可到達(dá)性:給定起點(diǎn)s ,是否有到指定頂點(diǎn)v的有向路徑.算法和DeepFirstSearch類(lèi)似.
多點(diǎn)可到達(dá)性:給定一個(gè)有向圖和頂點(diǎn)集合,回答”是否存在一條從集合中任意的頂點(diǎn)到達(dá)給定頂點(diǎn)v的有向路徑?”等類(lèi)似問(wèn)題.

4.2.3-1 標(biāo)記-清除 的垃圾回收器

多點(diǎn)可到達(dá)性的重要實(shí)際應(yīng)用在與 內(nèi)存管理系統(tǒng)中.對(duì)于java 內(nèi)存,在一個(gè)有向圖中,對(duì)象表示一個(gè)頂點(diǎn),引用表示一條邊.這個(gè)模型很好的解決了java內(nèi)存中.定期的進(jìn)行對(duì)有向圖的多點(diǎn)可到達(dá)性檢測(cè),發(fā)現(xiàn)有不可到達(dá)的頂點(diǎn)進(jìn)行回收的處理.

4.2.3-2 有向圖的尋路

DepthFirstPaths和breadthFirstPaths同樣適合有向圖.
單點(diǎn)有向圖 給定一個(gè)有向圖和起始頂點(diǎn):回答”從s到給定目的的頂點(diǎn)v是否存在一條有向路徑,如果有找出來(lái)”
單點(diǎn)最短有向路徑.”從s到給定目的地v是否存在一條路徑,如果存在找出其中最短的一條(所含的邊最少)”

4.2.4 環(huán)和有向無(wú)環(huán)圖

從原則上說(shuō),一副有向圖可能包含多個(gè)有向環(huán),但是實(shí)際上我們一般重點(diǎn)關(guān)注一小部分,或只想知道他們是否存在.


image.png
4.2.4.1 調(diào)度問(wèn)題

優(yōu)先級(jí)限制條件是調(diào)度問(wèn)題的核心,他指明了哪些任務(wù)必須在哪些任務(wù)之前完成. 這時(shí)候采用有向圖的方法來(lái)求解調(diào)度的順序就是很不錯(cuò)的.例如下圖

image.png

優(yōu)先級(jí)限制下的調(diào)度問(wèn)題: 解決這個(gè)問(wèn)題可以用有向圖來(lái)模型來(lái)表示.等價(jià)于 拓?fù)渑判?/strong>

image.png

拓?fù)渑判? 給定一個(gè)有向圖,將所有的頂點(diǎn)排序,使得所有的邊都是從排在前面的邊指向排在后面的邊.例如下面下邊示意圖:


image.png

拓?fù)渑判虻牡湫蛻?yīng)用:

應(yīng)用 頂點(diǎn)
任務(wù)調(diào)度 任務(wù) 優(yōu)先級(jí)限制
課程安排 課程 先導(dǎo)課程限制
繼承 java類(lèi) Extends 關(guān)系
符號(hào)鏈接 文件名 鏈接
4.2.4.2 有向圖中的環(huán)

在某些特定的有向圖依賴(lài)關(guān)系中是不允許出現(xiàn)環(huán)結(jié)構(gòu)的.例如java 類(lèi)依賴(lài)關(guān)系.
有向環(huán)檢測(cè): 如果有環(huán),在所有頂點(diǎn)中按照順序?qū)ふ?返回自己的頂點(diǎn).即找到了一個(gè)有向環(huán).
一幅有向圖的環(huán)的個(gè)數(shù)有可能是圖大小的指數(shù)級(jí)別,所以一般情況下只需要找到一個(gè)有向環(huán)即可判斷,而不需要找出所有的環(huán).因此有向無(wú)環(huán)圖就表現(xiàn)的尤為突出.

定義:

有向無(wú)環(huán)圖[DAG (Directed acyclic graph)]就是一副不含環(huán)的有向圖.

檢測(cè)是否是有向無(wú)環(huán)圖.采用深度優(yōu)先搜索.維護(hù)一個(gè)遞歸調(diào)用棧來(lái)記錄當(dāng)前在遍歷的有向路徑,一旦我們找到了一條邊v→ w ,并且w已經(jīng)存在當(dāng)前遞歸棧中,則表示找到了一個(gè)有向環(huán),同時(shí)如果找不到這樣一條邊,則說(shuō)明圖是有向無(wú)環(huán)圖.

package algorithm.algorithmbook.graph;
import java.util.Stack;
/**
 * description:尋找有向環(huán)
 *
 * @author leon
 * @date 18-2-26.
 */
public class DirectCycle {
    private int[] edgeTo;
    private boolean[] marked;
    //用于存放環(huán)的所有頂點(diǎn),如果存在環(huán)
    private Stack<Integer> cycles;
    //遞歸調(diào)用的棧上的所有頂點(diǎn)
    private boolean[] onStack;
    public DirectCycle(Digraph digraph) {
        onStack = new boolean[digraph.V()];
        marked = new boolean[digraph.V()];
        edgeTo = new int[digraph.V()];
        for (int v = 0; v < digraph.V(); v++) {
            if (!marked[v]) {
                dfs(digraph, v);
            }
        }
    }
    private void dfs(Digraph digraph, int v) {
        onStack[v] = true;
        marked[v] = true;
        for (int w : digraph.adj(v)) {
            //特別的處理環(huán)的,如果已經(jīng)找到了環(huán)則跳出循環(huán)
            if (this.hashCycle()) {
                return;
            }
            //進(jìn)行深度優(yōu)先遍歷
            if (!marked[w]) {
                edgeTo[w] = v;
                dfs(digraph, w);
            }
            //如果已經(jīng)marked了,說(shuō)明已經(jīng)查找過(guò)頂點(diǎn),也就是出現(xiàn)了環(huán)
            else if (onStack[w]) {
                cycles = new Stack<>();
                for (int x = v; x != w; x = edgeTo[x]) {
                    cycles.push(x);
                }
                cycles.push(w);
                cycles.push(v);
            }
            onStack[v] = false;
        }
    }
    public boolean hashCycle() {
        return !cycles.empty();
    }
    public Iterable<Integer> cycle() {
        return cycles;
    }
}
4.2.3.4 頂點(diǎn)的深度優(yōu)先次序和拓?fù)渑判?/h6>
命題E:

只有有向無(wú)環(huán)圖才能進(jìn)行拓?fù)渑判?

實(shí)際上我們已經(jīng)見(jiàn)過(guò)一種拓?fù)渑判虻乃惴?只需要添加一行代碼就可以由標(biāo)準(zhǔn)的深度優(yōu)先搜索完成這項(xiàng)任務(wù)!引入一種搜索排序,”有向圖中基于深度優(yōu)先的頂點(diǎn)搜索排序”.他的思想是深度優(yōu)先搜索只會(huì)訪問(wèn)所有的頂點(diǎn)一次.遍歷這個(gè)數(shù)據(jù)結(jié)構(gòu)實(shí)際上能訪問(wèn)圖中的所有頂點(diǎn),而遍歷的順序取決與這個(gè)數(shù)據(jù)結(jié)構(gòu)是遞歸前還是之后進(jìn)行保存.一般情況人們關(guān)注3中情況:

1.前序遍歷 (pre) :在遞歸前將頂點(diǎn)加入隊(duì)列

2.后續(xù)遍歷(post):在遞歸后將頂點(diǎn)加入隊(duì)列

3.逆后續(xù)(reversePost): 把后續(xù)遍歷的順序反轉(zhuǎn)采用棧保存,剛好可以反過(guò)來(lái)).在遞歸后將頂點(diǎn)加入棧.

待排序的有向圖
image.png

執(zhí)行深度優(yōu)先搜索的 3中排序過(guò)程:


image.png
package algorithm.algorithmbook.graph;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Stack;
/**
 * description:有向圖深度優(yōu)先排序的幾種方式
 * <p>
 * 這里根據(jù)在遞歸前,后 進(jìn)行頂點(diǎn)保存的順序分成前序,后序,逆后序
 * 1.前序遍歷 (pre) :在遞歸前將頂點(diǎn)加入隊(duì)列
 * 2.后續(xù)遍歷(post):在遞歸后將頂點(diǎn)加入隊(duì)列
 * 3.逆后續(xù)(reversePost): 把后續(xù)遍歷的順序反轉(zhuǎn)采用棧保存,剛好可以反過(guò)來(lái)).在遞歸后將頂點(diǎn)加入棧.
 *
 * @author leon
 * @date 18-2-27.
 */
public class DirectDeepFirstOrder {
    private boolean[] marked;
    private Queue<Integer> preQ;
    private Queue<Integer> postQ;
    private Stack<Integer> reversePost;
    public DirectDeepFirstOrder(Digraph g) {
        marked = new boolean[g.V()];
        preQ = new ArrayDeque<>();
        postQ = new ArrayDeque<>();
        reversePost = new Stack<>();
        for (int v = 0; v < g.V(); v++) {
            if (!marked[v]) {
                dfs(g, v);
            }
        }
    }
    /**
     * 深度優(yōu)先遍歷遞歸
     *
     * @param g 圖
     * @param v 需要遞歸的頂點(diǎn)
     */
    private void dfs(Digraph g, int v) {
        preQ.offer(v);
        marked[v] = true;
        for (int w : g.adj(v)) {
            if (!marked[w]) {
                dfs(g, w);
            }
        }
        postQ.offer(v);
        reversePost.push(v);
    }
    /**
     * 前序
     *
     * @return 排序列表
     */
    public Iterable<Integer> pre() {
        return preQ;
    }
    /**
     * 后序
     *
     * @return 排序列表
     */
    public Iterable<Integer> post() {
        return postQ;
    }
    /**
     * 逆后序
     *
     * @return 排序列表
     */
    public Iterable<Integer> reversePost() {
        return reversePost;
    }
}
命題:

一副有向無(wú)環(huán)圖的的拓?fù)渑判蚣此许旤c(diǎn)的逆后序排序

證明:

對(duì)于任意邊v→ w,在調(diào)用dfs(v)時(shí)以下三種情況之一會(huì)滿足:
1.dfs(w)已經(jīng)調(diào)用過(guò)并且已經(jīng)返回了(w已經(jīng)被標(biāo)記了)
2.dfs(w)還沒(méi)有調(diào)用,此時(shí)會(huì)繼續(xù)接下來(lái)調(diào)用dfs(w),并且在 dfs(v)之前調(diào)用,并且標(biāo)記.
3.dfs(w)已經(jīng)調(diào)用并且沒(méi)有返回.證明的關(guān)鍵在于,需要證明這種情況在有向無(wú)環(huán)圖中是不可能出現(xiàn)的,則可以確定v→ w 的dfs(x) 是有順序的.因?yàn)?如果 dfs(w)已經(jīng)調(diào)用,但是沒(méi)有返回,則說(shuō)明有邊w→ v存在,然而本身有v→ w ,這樣就形成了一個(gè)環(huán).與有向無(wú)環(huán)圖有矛盾,故情況3是不存在的.
綜上所述:任意一條邊的dfs(w) 都會(huì)在dfs(v)之前標(biāo)記,也就是說(shuō) 在排名靠后w的dfs(w) 比排名靠前v的dfs(v)先標(biāo)記,把標(biāo)記列表倒序就得到排名靠前的v→ w的頂點(diǎn).

package algorithm.algorithmbook.graph;
/**
 * description:拓?fù)渑判? *
 * @author leon
 * @date 18-2-26.
 */
public class Topological {
    private Iterable<Integer> orderList;
    public Topological(Digraph digraph) {
        DirectCycle directCycle = new DirectCycle(digraph);
        if (!directCycle.hashCycle()) {
            DirectDeepFirstOrder directDeepFirstOrder = new DirectDeepFirstOrder(digraph);
            orderList = directDeepFirstOrder.reversePost();
        }
    }
    /**
     * 是否是有向無(wú)環(huán)圖
     *
     * @return
     */
    public boolean isDAG() {
        return orderList != null;
    }
    /**
     * 拓?fù)渑判?     *
     * @return
     */
    Iterable<Integer> order() {
        return orderList;
    }
    /**
     * test
     *
     * @param args
     */
    public static void main(String[] args) {
        String fileName = args[0];
        String sepatetor = args[1];
        SymbolDirectGraph symbolGraph = new SymbolDirectGraph(fileName, sepatetor);
        Topological topological = new Topological(symbolGraph.graph());
        if (!topological.isDAG()) {
            return;
        }
        for (int v : topological.orderList) {
            //通過(guò)索引表來(lái)獲取圖中對(duì)應(yīng)的 名字
            System.out.println(symbolGraph.name(v));
        }
    }
}
命題G:

使用深度優(yōu)先搜索對(duì)無(wú)向圖進(jìn)行拓?fù)渑判虻乃钑r(shí)間與V+E成正比.

證明:

由代碼可知,拓?fù)渑判蛐枰M(jìn)行兩次,1.進(jìn)行是否有環(huán)判斷,2 進(jìn)行逆后序排序. 每次操作都訪問(wèn)了頂點(diǎn)和邊,即是V+E 的倍數(shù)關(guān)系.

4.2.5 有向圖中的強(qiáng)連通性
定義:

如果有向圖中 w和v 雙向可到達(dá)即存在v到w的有向路徑,也存在w到v的有向路徑,稱(chēng)為強(qiáng)連通.如果一副有向圖總?cè)我鈨牲c(diǎn)之間都是強(qiáng)連通,則稱(chēng)這幅有向圖也是強(qiáng)連通的.

兩個(gè)頂點(diǎn)是強(qiáng)連通.當(dāng)且僅當(dāng)他們都是同在一個(gè)有向環(huán)中.
強(qiáng)連通分量特點(diǎn):
  • 自反性:任意頂點(diǎn)v 和自己都是強(qiáng)連通的.
  • 對(duì)稱(chēng)性: v和w 是強(qiáng)連通,那么w和v也是強(qiáng)連通
  • 傳遞性: v和w 是強(qiáng)連通,w和x 是強(qiáng)連通.那么v 和x 是強(qiáng)連通.

強(qiáng)連通性將所有頂點(diǎn)分成一些平等的部分,每個(gè)部分是由所組成強(qiáng)連通的頂點(diǎn)最大子集組成.把這些最大子集稱(chēng)為強(qiáng)連通分量.包含V個(gè)頂點(diǎn)的有向圖包含 1-V個(gè)強(qiáng)連通分量;一個(gè)強(qiáng)連通圖只有一個(gè)強(qiáng)連通分量(也就是整個(gè)圖);而一個(gè)無(wú)環(huán)圖則包含V個(gè)強(qiáng)連通分量(每個(gè)頂點(diǎn)都是自己的強(qiáng)連通分量,所以強(qiáng)連通分量就是每個(gè)頂點(diǎn)).因?yàn)閺?qiáng)連通是針對(duì)頂點(diǎn)而不是邊,所以會(huì)出現(xiàn)有些邊連接的兩個(gè)頂點(diǎn)出現(xiàn)在同一個(gè)強(qiáng)連通分量中,而有些邊連接的兩個(gè)頂點(diǎn)則出現(xiàn)在不同的強(qiáng)連通分量中.


image.png
4.2.5.2 應(yīng)用舉例

在理解有向圖的結(jié)構(gòu)時(shí),強(qiáng)連通性是一個(gè)重要的特點(diǎn).他突出了相互關(guān)聯(lián)的幾組頂點(diǎn)(強(qiáng)連通分量).例如強(qiáng)連通分量能夠幫組教科書(shū)的作者決定那些話題應(yīng)該歸為一類(lèi),幫助程序員組織程序的模塊;表示哪些食物鏈中的物種應(yīng)該在一個(gè)生態(tài)圈中.
強(qiáng)連通分量API

SCC(digraph G) 構(gòu)造函數(shù)
Boolean stronglyConnetied(int v,int w) V ,w 是否是強(qiáng)連通
Int count() 強(qiáng)連通分量數(shù)
Int id(int v) V屬于哪個(gè)強(qiáng)連通分量(0 ~ count-1)
kosaraju算法:

1.在給定有向圖G,使用DeepFirstOrder計(jì)算他的反向圖GR的逆后序排序.

2.在G圖中進(jìn)行標(biāo)準(zhǔn)的深度優(yōu)先搜索,但是需要按照剛才計(jì)算出的順序訪問(wèn)所有未標(biāo)記過(guò)的頂點(diǎn)(而非標(biāo)準(zhǔn)的順序訪問(wèn)).

3.在構(gòu)造函數(shù)中,所有同一個(gè)遞歸dfs()調(diào)用中訪問(wèn)到的頂點(diǎn)都在同一個(gè)強(qiáng)連通分量中,將他們按照CC的方式識(shí)別出來(lái).

強(qiáng)連通性: 回答”給定的兩點(diǎn)是強(qiáng)連通的嗎? 這幅圖中含有多少個(gè)強(qiáng)連通分量 ?”

因?yàn)?Kosaraju 方法借助了有向圖求反向圖,然后再計(jì)算 逆序排序.

能不能用和 無(wú)向圖相同的效率解決有向圖圖的強(qiáng)連通問(wèn)題.Tarjan提出了一個(gè)解決方案.而且這個(gè)簡(jiǎn)單的解決方案令人驚訝.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捶索,更是在濱河造成了極大的恐慌惕医,老刑警劉巖油额,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悯舟,死亡現(xiàn)場(chǎng)離奇詭異患整,居然都是意外死亡眯停,警方通過(guò)查閱死者的電腦和手機(jī)济舆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)莺债,“玉大人滋觉,你說(shuō)我怎么就攤上這事签夭。” “怎么了椎侠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵第租,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我我纪,道長(zhǎng)慎宾,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任浅悉,我火速辦了婚禮趟据,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘术健。我一直安慰自己汹碱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布荞估。 她就那樣靜靜地躺著咳促,像睡著了一般。 火紅的嫁衣襯著肌膚如雪泼舱。 梳的紋絲不亂的頭發(fā)上等缀,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音娇昙,去河邊找鬼尺迂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冒掌,可吹牛的內(nèi)容都是我干的噪裕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼股毫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼膳音!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起铃诬,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤祭陷,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后趣席,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體兵志,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年宣肚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了想罕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡霉涨,死狀恐怖按价,靈堂內(nèi)的尸體忽然破棺而出惭适,到底是詐尸還是另有隱情,我是刑警寧澤楼镐,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布癞志,位于F島的核電站,受9級(jí)特大地震影響框产,放射性物質(zhì)發(fā)生泄漏今阳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一茅信、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧墓臭,春花似錦蘸鲸、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嗡载,卻和暖如春窑多,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背洼滚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工埂息, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遥巴。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓千康,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親铲掐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拾弃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容