[算法设计与分析-期末项目] Capacitated Facility Location Problem

题目描述

Suppose there are n facilities and m customers. We wish
to choose:
 (1) which of the n facilities to open
 (2) the assignment of customers to facilities
 The objective is to minimize the sum of the opening cost
and the assignment cost.
 The total demand assigned to a facility must not exceed
its capacity.

分析

将 m 个顾客分给 n 个设施,每个设施有打开费用 OpenCost,每个顾客对每个设施有不同的指派费用 AssignCost,每个设施都有自己的容量限制 Capacity, 每个顾客有自己的需求量 Demand。决定开放哪些设施并对顾客进行指派使得满足所有顾客的情况下,花费的费用最小

方法一:贪心

贪心可以在很快的速度下求出一个相对优的解。
将所有顾客的 AssignCost 从小到大排序,对于每个顾客,优先选择能容纳他的 AssignCost 最小的设施。

//  n : numFacility, m : numCustomer
int n, m;   
const int N = 55, M = 305;  

//  Capacity, OpeningCost, Demand, AssignmentCost
int cap[N], opc[N];    
int dmd[M], asc[M][N]; 

//  algorithm time
clock_t StartTime, EndTime;

//  mem for solve 
int FacOpenNum;
int CostAns;
bool FacOpen[N];
int FacCap[N];
int AssAns[M];
pair<int,int> SortedCos[N];
bool LocalOK;

bool cmpGreedy(pair<int, int> a, pair<int, int> b) {
    return a.first < b.first;
}

// greedy
void solveGreedy(string pName) {
    StartTime = clock();
    // init
    CostAns = 0;
    FacOpenNum = 0;
    memset(FacOpen, false, sizeof(FacOpen));
    memset(FacCap, 0, sizeof(FacCap));
    memset(AssAns, 0, sizeof(AssAns));
    for (int i = 0; i < m; i++) {
        //   sort assignmentcost
        for (int j = 0; j < n; j++) {
            SortedCos[j].first = asc[i][j];
            SortedCos[j].second = j;
        }
        sort(SortedCos, SortedCos + n, cmpGreedy);
        //  choose a fac to assign
        for (int j = 0; j < n; j++) {
            int NowCos = SortedCos[j].first;
            int FacNum = SortedCos[j].second;
            // cout << NowCos << endl;
            //  can assign
            if (FacCap[FacNum] + dmd[i] <= cap[FacNum]) {
                if (!FacOpen[FacNum]) {
                    FacOpenNum++;
                    CostAns += opc[FacNum];
                    FacOpen[FacNum] = true;
                }
                FacCap[FacNum] += dmd[i];
                CostAns += NowCos;
                AssAns[i] = FacNum + 1;
                break;
            }
        }
    }
    EndTime = clock();
}

方法二:模拟退火

模拟退火算法维持一个温度 T,在某一温度下进行多次邻域搜索,如果新解优于旧解,则接受;如果弱于旧解,则概率接受。
该概率描述为 P(T, delta) = e^{ - \frac {delta} {T} }
其中 delta = newCost - oldCost
每进行一批邻域搜索后进行降温,一般描述为 T = \alpha T, 通常 \alpha 选择 [ 0.5, 0.99 ] 中的某个值。

对于该问题,我们设计邻域操作时需要考虑将所有的状态包含进去。
基于此,设计以下四种邻域:
1)将某个顾客移动到另一个设施
2)将两个设施的某两个顾客交换
3)打开一个关闭的工厂并将某个顾客移入该工厂
4)关闭一个打开的工厂并将其所有顾客随机移入其他工厂

这四种邻域以相等概率进行。
关于不合法的邻域,采用直接抛弃的办法,并进行下一次邻域。
每次邻域维护一堆局部状态量,如果合格,将其复制到全局最优状态量中。
每个温度下进行 200000 次 邻域操作

初解采用贪心解。

//  mem for SA Local srch
int SA_FON;
bool SA_FO[N];
int SA_FC[N];
int SA_AA[M];

double probSA(double temp, double delta) {
    return exp(-delta / temp);
}
double randSA() {
    return rand() / (double)RAND_MAX;
}
int solveLocal();
double coldSA(double temp) {
    return temp * 0.9;
}
void cpyCenterToLocal() {
    SA_FON = FacOpenNum;
    for (int i = 0; i < n; i++) {
        SA_FO[i] = FacOpen[i];
        SA_FC[i] = FacCap[i];
    }
    for (int i = 0; i < m; i++) {
        SA_AA[i] = AssAns[i];
    }
}
void cpyLocalToCenter() {
    FacOpenNum = SA_FON;
    for (int i = 0; i < n; i++) {
        FacOpen[i] = SA_FO[i];
        FacCap[i] = SA_FC[i];
    }
    for (int i = 0; i < m; i++) {
        AssAns[i] = SA_AA[i];
    }
}

// simulation Annealing
void solveSA(string pName) {
    // greedy to init
    // include StartTime
    solveGreedy(pName);
    // SA init
    double T = 100;
    srand(time(NULL));
    // SA
    while (T > 0.1) {
        // Local Srch 200000 times
        for (int i = 0; i < 200000; i++) {
            int NewCost = solveLocal();
            if ( randSA() <= probSA(T, NewCost - CostAns) && LocalOK) {
                // change to new state
                CostAns = NewCost;
                cpyLocalToCenter();
            }
        }
        // cold temparature
        T = coldSA(T);
    }
    // renew EndTime
    EndTime = clock();
}

int solveLocal() {
    srand(time(NULL));
    int NewCost = CostAns;
    LocalOK = true;
    cpyCenterToLocal();
    double WayProb = randSA();
    if (WayProb >= 0 && WayProb < 0.25) {
        //  choose way 1: change a cus to another fac
        int CusNum = randSA() * m;
        int FacNum = randSA() * n;
        //  fac is not open or cannot accept the cus
        // directly return
        if (!SA_FO[FacNum] || SA_FC[FacNum] + dmd[CusNum] > cap[FacNum]) {
            return NewCost;
        }
        int OldFac = SA_AA[CusNum];
        SA_AA[CusNum] = FacNum;
        SA_FC[FacNum] += dmd[CusNum];
        SA_FC[OldFac] -= dmd[CusNum];
        NewCost = NewCost + asc[CusNum][FacNum] - asc[CusNum][OldFac];
    } else if (WayProb >= 0.25 && WayProb < 0.5) {
        // choose way 2: switch 2 cus
        int Cus1 = randSA() * m;
        int Cus2 = randSA() * m;
        int Fac1 = SA_AA[Cus1];
        int Fac2 = SA_AA[Cus2];
        // cannot switch 
        // directly return
        if (Cus1 == Cus2 ||
                SA_FC[Fac1] - dmd[Cus1] + dmd[Cus2] > cap[Fac1] ||
                SA_FC[Fac2] - dmd[Cus2] + dmd[Cus1] > cap[Fac2]   ) {
            return NewCost;    
        }
        SA_AA[Cus1] = Fac2;
        SA_AA[Cus2] = Fac1;
        SA_FC[Fac1] = SA_FC[Fac1] - dmd[Cus1] + dmd[Cus2];
        SA_FC[Fac2] = SA_FC[Fac2] - dmd[Cus2] + dmd[Cus1];
        NewCost = NewCost + (asc[Cus1][Fac2] - asc[Cus1][Fac1])
                          + (asc[Cus2][Fac1] - asc[Cus2][Fac2]);
    } else if (WayProb >= 0.5 && WayProb < 0.75) {
        // choose way 3: open a fac and change 1 cus to it
        // no closed fac to open
        if (SA_FON == n) return NewCost;
        int FacNum = randSA() * n;
        // randomed fac is open
        if (SA_FO[FacNum]) {
            return NewCost;
        }
        int CusNum = randSA() * m;
        // cannot accept
        if (SA_FC[FacNum] + dmd[CusNum] > cap[FacNum]) {
            return NewCost;
        }
        int OldFac = SA_AA[CusNum];
        SA_FON++;
        SA_FO[FacNum] = true;
        SA_FC[FacNum] += dmd[CusNum];
        SA_FC[OldFac] -= dmd[CusNum];
        SA_AA[CusNum] = FacNum;
        NewCost = NewCost - asc[CusNum][OldFac] + asc[CusNum][FacNum] + opc[FacNum];
    } else {
        // choose way 4: close a fac and random its cus to others
        // no open fac to close
        if (SA_FON == 0) return NewCost;
        int FacNum = randSA() * n;
        // randomed fac is closed
        if (!SA_FO[FacNum]) {
            return NewCost;
        }
        // record cus in the fac
        vector<int> FacNumList;
        vector<int> NewFacList;
        for (int i = 0; i < m; i++) {
            if (SA_AA[i] == FacNum) {
                FacNumList.push_back(i);
            }
        }
        // random cus to other facs
        SA_FON--;
        SA_FO[FacNum] = false;
        SA_FC[FacNum] = 0;
        int NowNewCost = NewCost;
        NowNewCost -= opc[FacNum];
        for (int i = 0; i < FacNumList.size(); i++) {
            int CusNum = FacNumList[i];
            int NewFac = randSA() * n;
            // cannot accept
            // cnt to record iter times, limit be sure can jump out
            int cnt = 1;
            int limit = 10 * n;
            while ( (!SA_FO[NewFac] || SA_FC[NewFac] + dmd[CusNum] > cap[NewFac]) && cnt < limit ) {
                NewFac = randSA() * n;
                cnt++;
            }
            // prob cannot close the fac to accept people
            // directly return
            if (cnt >= limit) {
                LocalOK = false;
                return NewCost;
            }
            SA_FC[NewFac] += dmd[CusNum]; 
            SA_AA[CusNum] = NewFac;
            NowNewCost = NowNewCost - asc[CusNum][FacNum] + asc[CusNum][NewFac];
        }
        NewCost = NowNewCost;
    }
    return NewCost;
}

结果及对比

结果及算法时间

数据组数 贪心算法结果 贪心算法时间 模拟退火结果 模拟退火时间
p1 10355 0.000 10355 6.233
p2 9041 0.000 9041 5.256
p3 11041 0.000 11041 5.407
p4 13041 0.000 13041 5.223
p5 10827 0.000 10827 5.183
p6 9513 0.000 8627 6.223
p7 11513 0.000 8145 6.501
p8 13513 0.000 10876 6.768
p9 10355 0.000 8179 5.380
p10 9041 0.000 5831 5.282
p11 11041 0.000 7369 6.410
p12 13041 0.001 7322 6.249
p13 11915 0.000 10494 6.249
p14 9426 0.000 6997 6.118
p15 13026 0.001 9549 6.685
p16 16626 0.000 10554 7.903
p17 11915 0.000 10128 6.312
p18 9426 0.000 7854 6.051
p19 13026 0.000 11372 6.284
p20 16626 0.000 14411 6.182
p21 11915 0.000 10429 6.069
p22 9426 0.000 8193 7.565
p23 13026 0.000 10106 6.125
p24 16626 0.000 12443 6.075
p25 16673 0.001 12738 18.353
p26 14143 0.001 8497 14.289
p27 18943 0.001 14576 18.137
p28 23743 0.001 20231 20.747
p29 17463 0.001 14094 17.326
p30 14726 0.001 8146 18.188
p31 19926 0.000 15329 22.010
p32 25126 0.001 19371 16.434
p33 16597 0.001 8870 15.846
p34 14067 0.001 12635 21.744
p35 18867 0.001 15239 17.863
p36 23667 0.000 15990 15.962
p37 16597 0.001 13719 17.454
p38 14067 0.001 12791 18.602
p39 18867 0.001 15292 17.765
p40 23667 0.001 10325 17.017
p41 8853 0.000 7717 9.596
p42 10681 0.001 9512 10.004
p43 13592 0.000 11804 8.789
p44 12280 0.000 11241 16.254
p45 12949 0.000 10727 8.770
p46 14646 0.000 12122 9.176
p47 14162 0.000 12553 13.164
p48 13980 0.000 12692 9.619
p49 12846 0.001 11286 10.089
p50 10106 0.000 9351 21.064
p51 10778 0.000 9393 12.079
p52 15442 0.000 14814 10.625
p53 14438 0.000 12706 9.445
p54 15941 0.000 14769 9.980
p55 14113 0.000 12384 12.059
p56 14822 0.000 9642 18.622
p57 23522 0.001 14442 17.736
p58 43822 0.001 25228 18.119
p59 29230 0.001 18318 18.707
p60 14822 0.000 9466 16.490
p61 23522 0.001 15856 17.382
p62 43822 0.001 30125 16.425
p63 29230 0.000 20544 16.490
p64 14822 0.001 10469 16.411
p65 23522 0.001 13895 18.075
p66 43822 0.001 28710 19.358
p67 31192 0.001 17227 22.205
p68 14822 0.001 7813 22.066
p69 23522 0.000 14995 20.138
p70 43822 0.001 28849 18.134
p71 29230 0.001 16904 17.714

贪心算法具体结果

石墨文档

模拟退火具体结果

石墨文档

代码总览

#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <utility>
#include <ctime>
#include <iomanip>
#include <vector>
using namespace std;

//  n : numFacility, m : numCustomer
int n, m;   
const int N = 55, M = 305;  

//  Capacity, OpeningCost, Demand, AssignmentCost
int cap[N], opc[N];    
int dmd[M], asc[M][N]; 

//  algorithm time
clock_t StartTime, EndTime;

//  mem for solve 
int FacOpenNum;
int CostAns;
bool FacOpen[N];
int FacCap[N];
int AssAns[M];
pair<int,int> SortedCos[N];
bool LocalOK;

//  mem for SA Local srch
int SA_FON;
bool SA_FO[N];
int SA_FC[N];
int SA_AA[M];

//  mem for results
vector<double> GTimers;
vector<double> SATimers;
vector<int> GResult;
vector<int> SAResult;

void solveGreedy(string pName);
bool cmpGreedy(pair<int, int> a, pair<int, int> b) {
    return a.first < b.first;
}
void solveSA(string pName);
void inputData(string FileName);
void outputGreedy(string pName);
void outputSA(string pName);
double probSA(double temp, double delta) {
    return exp(-delta / temp);
}
double randSA() {
    return rand() / (double)RAND_MAX;
}
int solveLocal();
double coldSA(double temp) {
    return temp * 0.9;
}
void cpyCenterToLocal() {
    SA_FON = FacOpenNum;
    for (int i = 0; i < n; i++) {
        SA_FO[i] = FacOpen[i];
        SA_FC[i] = FacCap[i];
    }
    for (int i = 0; i < m; i++) {
        SA_AA[i] = AssAns[i];
    }
}
void cpyLocalToCenter() {
    FacOpenNum = SA_FON;
    for (int i = 0; i < n; i++) {
        FacOpen[i] = SA_FO[i];
        FacCap[i] = SA_FC[i];
    }
    for (int i = 0; i < m; i++) {
        AssAns[i] = SA_AA[i];
    }
}

void outputGTimers() {
    ofstream GTOut;
    GTOut.open("GResult");
    for (int i = 0; i < GTimers.size(); i++) {
        GTOut << "p" + to_string(i + 1) << " ";
        GTOut << GResult[i] << " ";
        GTOut << fixed << setprecision(3) << GTimers[i] << endl;
    }
}

void outputSATimers() {
    ofstream SATOut;
    SATOut.open("SAResult");
    for (int i = 0; i < SATimers.size(); i++) {
        SATOut << "p" + to_string(i + 1) << " ";
        SATOut << SAResult[i] << " ";
        SATOut << fixed << setprecision(3) << SATimers[i] << endl;
    }
}

int main() {
    for (int i = 1; i <= 71; i++) {
        string pName = "p" + to_string(i);
        string fileName = "Instances/" + pName;
        inputData(fileName);
        // solveGreedy(pName);
        // outputGreedy(pName);
        solveSA(pName);
        outputSA(pName);
        
    }
    // outputGTimers();
    outputSATimers();
    // system("pause");
    return 0;
}

// greedy
void solveGreedy(string pName) {
    StartTime = clock();
    // init
    CostAns = 0;
    FacOpenNum = 0;
    memset(FacOpen, false, sizeof(FacOpen));
    memset(FacCap, 0, sizeof(FacCap));
    memset(AssAns, 0, sizeof(AssAns));
    for (int i = 0; i < m; i++) {
        //   sort assignmentcost
        for (int j = 0; j < n; j++) {
            SortedCos[j].first = asc[i][j];
            SortedCos[j].second = j;
        }
        sort(SortedCos, SortedCos + n, cmpGreedy);
        //  choose a fac to assign
        for (int j = 0; j < n; j++) {
            int NowCos = SortedCos[j].first;
            int FacNum = SortedCos[j].second;
            // cout << NowCos << endl;
            //  can assign
            if (FacCap[FacNum] + dmd[i] <= cap[FacNum]) {
                if (!FacOpen[FacNum]) {
                    FacOpenNum++;
                    CostAns += opc[FacNum];
                    FacOpen[FacNum] = true;
                }
                FacCap[FacNum] += dmd[i];
                CostAns += NowCos;
                AssAns[i] = FacNum + 1;
                break;
            }
        }
    }
    EndTime = clock();
}

// simulation Annealing
void solveSA(string pName) {
    // greedy to init
    // include StartTime
    solveGreedy(pName);
    // SA init
    double T = 100;
    srand(time(NULL));
    // SA
    while (T > 0.1) {
        // Local Srch 200000 times
        for (int i = 0; i < 200000; i++) {
            int NewCost = solveLocal();
            if ( randSA() <= probSA(T, NewCost - CostAns) && LocalOK) {
                // change to new state
                CostAns = NewCost;
                cpyLocalToCenter();
            }
        }
        // cold temparature
        T = coldSA(T);
    }
    // renew EndTime
    EndTime = clock();
}

int solveLocal() {
    srand(time(NULL));
    int NewCost = CostAns;
    LocalOK = true;
    cpyCenterToLocal();
    double WayProb = randSA();
    if (WayProb >= 0 && WayProb < 0.25) {
        //  choose way 1: change a cus to another fac
        int CusNum = randSA() * m;
        int FacNum = randSA() * n;
        //  fac is not open or cannot accept the cus
        // directly return
        if (!SA_FO[FacNum] || SA_FC[FacNum] + dmd[CusNum] > cap[FacNum]) {
            return NewCost;
        }
        int OldFac = SA_AA[CusNum];
        SA_AA[CusNum] = FacNum;
        SA_FC[FacNum] += dmd[CusNum];
        SA_FC[OldFac] -= dmd[CusNum];
        NewCost = NewCost + asc[CusNum][FacNum] - asc[CusNum][OldFac];
    } else if (WayProb >= 0.25 && WayProb < 0.5) {
        // choose way 2: switch 2 cus
        int Cus1 = randSA() * m;
        int Cus2 = randSA() * m;
        int Fac1 = SA_AA[Cus1];
        int Fac2 = SA_AA[Cus2];
        // cannot switch 
        // directly return
        if (Cus1 == Cus2 ||
                SA_FC[Fac1] - dmd[Cus1] + dmd[Cus2] > cap[Fac1] ||
                SA_FC[Fac2] - dmd[Cus2] + dmd[Cus1] > cap[Fac2]   ) {
            return NewCost;    
        }
        SA_AA[Cus1] = Fac2;
        SA_AA[Cus2] = Fac1;
        SA_FC[Fac1] = SA_FC[Fac1] - dmd[Cus1] + dmd[Cus2];
        SA_FC[Fac2] = SA_FC[Fac2] - dmd[Cus2] + dmd[Cus1];
        NewCost = NewCost + (asc[Cus1][Fac2] - asc[Cus1][Fac1])
                          + (asc[Cus2][Fac1] - asc[Cus2][Fac2]);
    } else if (WayProb >= 0.5 && WayProb < 0.75) {
        // choose way 3: open a fac and change 1 cus to it
        // no closed fac to open
        if (SA_FON == n) return NewCost;
        int FacNum = randSA() * n;
        // randomed fac is open
        if (SA_FO[FacNum]) {
            return NewCost;
        }
        int CusNum = randSA() * m;
        // cannot accept
        if (SA_FC[FacNum] + dmd[CusNum] > cap[FacNum]) {
            return NewCost;
        }
        int OldFac = SA_AA[CusNum];
        SA_FON++;
        SA_FO[FacNum] = true;
        SA_FC[FacNum] += dmd[CusNum];
        SA_FC[OldFac] -= dmd[CusNum];
        SA_AA[CusNum] = FacNum;
        NewCost = NewCost - asc[CusNum][OldFac] + asc[CusNum][FacNum] + opc[FacNum];
    } else {
        // choose way 4: close a fac and random its cus to others
        // no open fac to close
        if (SA_FON == 0) return NewCost;
        int FacNum = randSA() * n;
        // randomed fac is closed
        if (!SA_FO[FacNum]) {
            return NewCost;
        }
        // record cus in the fac
        vector<int> FacNumList;
        vector<int> NewFacList;
        for (int i = 0; i < m; i++) {
            if (SA_AA[i] == FacNum) {
                FacNumList.push_back(i);
            }
        }
        // random cus to other facs
        SA_FON--;
        SA_FO[FacNum] = false;
        SA_FC[FacNum] = 0;
        int NowNewCost = NewCost;
        NowNewCost -= opc[FacNum];
        for (int i = 0; i < FacNumList.size(); i++) {
            int CusNum = FacNumList[i];
            int NewFac = randSA() * n;
            // cannot accept
            // cnt to record iter times, limit be sure can jump out
            int cnt = 1;
            int limit = 10 * n;
            while ( (!SA_FO[NewFac] || SA_FC[NewFac] + dmd[CusNum] > cap[NewFac]) && cnt < limit ) {
                NewFac = randSA() * n;
                cnt++;
            }
            // prob cannot close the fac to accept people
            // directly return
            if (cnt >= limit) {
                LocalOK = false;
                return NewCost;
            }
            SA_FC[NewFac] += dmd[CusNum]; 
            SA_AA[CusNum] = NewFac;
            NowNewCost = NowNewCost - asc[CusNum][FacNum] + asc[CusNum][NewFac];
        }
        NewCost = NowNewCost;
    }
    return NewCost;
}

//   handle input
void inputData(string FileName) {
    // cout << FileName << endl;
    ifstream pi;
    pi.open(FileName.c_str());
    char dot;

    pi >> n >> m;
    // cout << n << endl;
    // cout << m << endl;
    // cout << FileName << endl;
    for (int i = 0; i < n; i++) {
        pi >> cap[i] >> opc[i];
        // cout << cap[i] << endl;
    }
    for (int i = 0; i < m; i++) {
        pi >> dmd[i] >> dot;
        // cout << dmd[i] << endl;
    }
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            pi >> asc[i][j] >> dot;
        }
    }
    pi.close();
}

void outputGreedy(string pName) {
    string FoutName = "GAnswers/" + pName;
    ofstream po;
    po.open(FoutName);

    GResult.push_back(CostAns);
    po << CostAns << endl;
    for (int i = 0; i < n; i++) {
        po << FacOpen[i] << " ";
    }
    po << endl;
    for (int i = 0; i < m; i++) {
        po << AssAns[i] << " ";
    }
    po << endl;

    double timeUsed = (double) (EndTime - StartTime) / CLOCKS_PER_SEC;
    // po << fixed << setprecision(3) << timeUsed << endl;
    GTimers.push_back(timeUsed);

    po.close();
}

void outputSA(string pName) {
    string FoutName = "SAAnswers/" + pName;
    ofstream po;
    po.open(FoutName);

    SAResult.push_back(CostAns);
    po << CostAns << endl;
    for (int i = 0; i < n; i++) {
        po << FacOpen[i] << " ";
    }
    po << endl;
    for (int i = 0; i < m; i++) {
        po << AssAns[i] << " ";
    }
    po << endl;

    double timeUsed = (double) (EndTime - StartTime) / CLOCKS_PER_SEC;
    // po << fixed << setprecision(3) << timeUsed << endl;
    SATimers.push_back(timeUsed);

    po.close();
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容