Cplex 學習筆記 2 - 第一個Cplex求解的C#程序

本教程內容大部分來自Cplex官方文檔掖桦,若涉及侵權請聯系我刪除

介紹教程

.NET框架中的CPLEX支持創(chuàng)建模型冕香,使用數據填充模型儒喊,解決問題以及顯示解決方案的結果镣奋。
本教程通過.NET框架中的Concert Technology介紹CPLEX。它概述了典型應用程序并強調了以下過程:

創(chuàng)建模型

  • 使用數據(按行怀愧,按列或非零)填充模型
  • 求解這個模型
  • 求解后顯示結果

本章重點介紹使用C#.NET的示例侨颈。您還可以在你的Cplex文件夾中隨CPLEX 一起提供的VB.NET(.NET框架中的Visual Basic)示例\例子\ SRC \ VB。由于它們的.NET框架芯义,這些VB.NET示例與某些CPLEX用戶可能已經熟悉的傳統Visual Basic示例不同哈垢。

你將要做什么

本教程將指導您在C#.NET中構建和解決一個小規(guī)模的線性規(guī)劃模型。

CPLEX可以與Concert Technology for .NET用戶一起使用毕贼,這是一個.NET庫温赔,允許您獨立于用于解決問題的算法來建模優(yōu)化問題。它提供了一個可擴展的建模層鬼癣,適用于現成的各種算法陶贼。此建模層使您可以更改模型,而無需完全重寫應用程序待秃。

要通過CPLEX with Concert Technology for .NET用戶找到問題的解決方案拜秧,可以使用三階段方法:describe,model和solve章郁。

  • 第一階段是用自然語言描述問題枉氮。

  • 第二階段是使用Concert Technology for .NET用戶的類和接口來模擬問題。該模型由數據暖庄,決策變量和約束組成聊替。決策變量是問題中的未知信息。每個決策變量都有一個可能值的域培廓。約束是對這些決策變量的值組合的限制或限制惹悄。該模型還可以包含目標,可以最大化或最小化的表達肩钠。

  • 第三階段是使用Concert Technology for .NET用戶的類來解決問題泣港。解決問題包括為每個決策變量找到一個值,同時滿足約束條件价匠,并最大化或最小化一個目標(如果一個目標包含在模型中)当纱。

描述

第一步是用自然語言描述問題并回答有關問題的基本問題。

  • 這個問題中的已知信息是什么踩窖?也就是說坡氯,有哪些數據?

  • 這個問題中的未知信息是什么?也就是說箫柳,決策變量是什么颓遏?

  • 這個問題有什么限制?也就是說滞时,決策變量的約束是什么?

  • 解決這個問題的目的是什么滤灯?也就是說坪稽,目標函數是什么?

注意:

雖然這個過程的描述步驟在像這樣的簡單問題中看似微不足道鳞骤,但您會發(fā)現花時間充分描述更復雜的問題對于創(chuàng)建成功的應用程序至關重要窒百。如果您花時間描述模型,隔離決策變量豫尽,約束和目標篙梢,您將能夠更快速有效地編寫應用程序代碼。

模型

第二階段是讓您使用Concert Technology for .NET用戶的類來構建問題模型美旧。該模型由決策變量和對這些變量的約束組成渤滞。這個問題的模型也包含一個目標

解決

第三階段是您使用CPLEX類的實例尋找解決方案并解決問題榴嗅。解決問題包括為每個變量找到一個值妄呕,同時滿足約束并最小化目標。

描述

提出這些問題來充分描述應用程序開發(fā)的優(yōu)化問題嗽测。

本教程的目的是查看構建模型的三種不同方法:按行绪励,按列或按非零。在以這些方式之一構建問題模型之后唠粥,應用程序優(yōu)化問題并顯示解決方案疏魏。

第一步:描述問題

寫出問題的自然語言描述并回答以下問題:
對這個問題了解多少?
這個問題中有哪些未知的信息(決策變量)晤愧?
決策變量有哪些限制(約束)大莫?
解決這個問題的目的(目標)是什么?

在C#中構建一個小LP問題
以下是該示例優(yōu)化的問題的傳統公式:

Max x1 + 2x2 + 3x3
Subject to.
-x1 + x2 + x3 ≤ 20
x1 - 3x2 + x3 ≤ 30
0 ≤ x1 ≤ 40
0 ≤ x2 ≤ ∞
0 ≤ x3 ≤ ∞

  • 這個問題的決策變量是什么养涮?
    x1葵硕,x2,x3

  • 有什么限制贯吓?
    -x1 + x2 + x3 ≤ 20
    x1 - 3x2 + x3 ≤ 30
    0 ≤ x1 ≤ 40
    0 ≤ x2 ≤ ∞
    0 ≤ x3 ≤ ∞

  • 目標是什么懈凹?

    Max x1 + 2x2 + 3x3

模型

使用Concert Technology for .NET用戶類來構建問題的模型。
在編寫問題描述之后悄谐,可以使用Concert Technology for .NET用戶和CPLEX類來構建模型介评。

第2步:打開文件

打開yourCPLEXhome文件 \實例的\ src \教程\ LPex1lesson.cs 在您的集成開發(fā)環(huán)境中,例如Microsoft Visual Studio。

第3步:創(chuàng)建模型對象

轉到該文件中的注釋步驟3们陆,并添加此語句以創(chuàng)建CPLEX 適合您的應用的模型寒瓦。

Cplex cplex = new Cplex();

該語句創(chuàng)建了一個類的空實例 CPLEX。在接下來的步驟中坪仇,您將添加一些方法杂腰,使您的應用程序可以使用行,按列或非零數據為數據填充數據椅文。

第4步:按行填充模型

現在轉到該文件中的注釋步驟4喂很,并添加這些行以創(chuàng)建一個方法,用行按數據填充空模型皆刺。

 internal static void PopulateByRow(IMPModeler model,
                                  INumVar[][] var,
                                  IRange[][] rng) {
 double[] lb = {0.0, 0.0, 0.0};
 double[] ub = {40.0, 
                System.Double.MaxValue, 
                System.Double.MaxValue};
 INumVar[] x  = model.NumVarArray(3, lb, ub);
 var[0] = x;

 double[] objvals = {1.0, 2.0, 3.0};
 model.AddMaximize(model.ScalProd(x, objvals));

 rng[0] = new IRange[2];
 rng[0][0] = model.AddLe(model.Sum(model.Prod(-1.0, x[0]),
                                   model.Prod( 1.0, x[1]),
                                   model.Prod( 1.0, x[2])), 20.0);
 rng[0][1] = model.AddLe(model.Sum(model.Prod( 1.0, x[0]),
                                   model.Prod(-3.0, x[1]),
                                   model.Prod( 1.0, x[2])), 30.0);
 }

這些行使用特定于此特定示例的數據填充模型少辣。但是,您可以從它的使用界面中看到IMPModeler 如何將遠程約束 s 添加到模型中羡蛾。IMPModeler 是Concert Technology界面漓帅,通常用于構建數學編程(MP)矩陣模型。您將在步驟5和步驟6中再次看到它的用途痴怨。

第5步:按列填充模型

轉到文件中的注釋步驟5忙干,并添加這些行以創(chuàng)建一個方法,用列按數據填充空模型腿箩。

 internal static void PopulateByColumn(IMPModeler model,
                            INumVar[][] var,
                            IRange[][] rng) {
  IObjective obj = model.AddMaximize();

  rng[0] = new IRange[2];
  rng[0][0] = model.AddRange(-System.Double.MaxValue, 20.0);
  rng[0][1] = model.AddRange(-System.Double.MaxValue, 30.0);

  IRange r0 = rng[0][0];
  IRange r1 = rng[0][1];

  var[0] = new INumVar[3];
  var[0][0] = model.NumVar(model.Column(obj,  1.0).And(
                           model.Column(r0,  -1.0).And(
                           model.Column(r1,   1.0))),
                           0.0, 40.0);
  var[0][1] = model.NumVar(model.Column(obj,  2.0).And(
                           model.Column(r0,   1.0).And(
                           model.Column(r1,  -3.0))),
                           0.0, System.Double.MaxValue);
  var[0][2] = model.NumVar(model.Column(obj,  3.0).And(
                           model.Column(r0,   1.0).And(
                           model.Column(r1,   1.0))),
                           0.0, System.Double.MaxValue);
 }

同樣豪直,這些行使用特定于此問題的數據填充模型。從中他們可以看到如何使用界面IMPModeler 將列添加到空模型珠移。

雖然對于許多示例而言弓乙,按行顯示可能看起來最簡單和自然,但是有些模型按行列出是更自然或更有效的實現方法钧惧。例如暇韧,網絡結構問題通常很適合按列建模。熟悉矩陣代數的讀者可以查看該方法populateByColumn 作為的轉置 populateByRow 浓瞪。

在此方法中懈玻,創(chuàng)建范圍對象以按列建模,僅具有其下限和上限乾颁。沒有給出變量的表達式涂乌,因為在這一點上構建它們是不可能的,因為還沒有創(chuàng)建變量英岭。類似地湾盒,目標函數僅在其預期的優(yōu)化意義下創(chuàng)建,并且沒有任何表達诅妹。

接下來罚勾,創(chuàng)建變量并將其安裝在現有范圍和目標中毅人。這些新創(chuàng)建的變量通過列對象引入范圍和目標,列對象在類中實現IColumn尖殃。使用這些方法創(chuàng)建此類的對象Cplex.Column丈莺,可以與方法鏈接在一起 IColumn.And 形成聚合 IColumn 對象。

一個 IColumn 用該方法創(chuàng)建的對象 ICplex.Column包含有關如何使用此列將新變量引入現有建模對象的信息送丰。例如缔俄,如果OBJ 是一個 IObjective 賓語, cplex.Column(obj器躏,2.0) 創(chuàng)造一個 IColumn 包含在表達式中安裝新變量的信息的對象 IObjective 賓語 OBJ 線性系數為 2.0牵现。同樣,對于IRange 約束 RNG 邀桑,方法調用 cplex.Column(rng,-1.0) 創(chuàng)造一個 IColumn 包含要在表達式中安裝新變量的信息的對象 RNG 科乎,作為系數的線性項 -1.0 壁畸。

簡而言之,當您使用逐列建模方法時茅茂,會創(chuàng)建新列并將其作為變量安裝在需要它們的所有現有建模對象中捏萍。要使用Concert Technology執(zhí)行此操作,您需要創(chuàng)建一個IColumn 您要在其中安裝新變量的每個建模對象的對象空闲,并使用該方法將它們鏈接在一起 IColumn.And 令杈。

第6步:使用非零填充模型

轉到文件中的注釋步驟6,并添加這些行以創(chuàng)建一個方法碴倾,用非零的數據填充空模型逗噩。

internal static void PopulateByNonzero(IMPModeler model,
                             INumVar[][] var,
                             IRange[][] rng) {
  double[]    lb = {0.0, 0.0, 0.0};
  double[]    ub = {40.0, System.Double.MaxValue, System.Double.MaxValue};
  INumVar[] x  = model.NumVarArray(3, lb, ub);
  var[0] = x;

  double[] objvals = {1.0, 2.0, 3.0};
  model.Add(model.Maximize(model.ScalProd(x, objvals)));

  rng[0] = new IRange[2];
  rng[0][0] = model.AddRange(-System.Double.MaxValue, 20.0);
  rng[0][1] = model.AddRange(-System.Double.MaxValue, 30.0);

  rng[0][0].Expr = model.Sum(model.Prod(-1.0, x[0]),
                             model.Prod( 1.0, x[1]),
                             model.Prod( 1.0, x[2]));
  rng[0][1].Expr = model.Sum(model.Prod( 1.0, x[0]),
                             model.Prod(-3.0, x[1]),
                             model.Prod( 1.0, x[2]));
 }

在這些行中,您可以看到如何使用指示約束矩陣的非零的數據填充空模型跌榔。這些行首先為目標和沒有表達式的范圍創(chuàng)建對象异雁。他們還創(chuàng)建沒有列的變量; 也就是說,只有邊界的變量僧须。然后纲刀,這些行在目標,范圍和變量上創(chuàng)建表達式担平,并將表達式添加到模型中示绊。

第7步:添加界面

轉到文件中的注釋步驟7,并添加這些行以創(chuàng)建一個方法暂论,告訴用戶如何調用此應用程序面褐。

 internal static void Usage() {
    System.Console.WriteLine(“usage:   LPex1 <option>”);
    System.Console.WriteLine(“options: -r   build model row by row”);
    System.Console.WriteLine(“options: -c   build model column by column”);
    System.Console.WriteLine(“options: -n   build model nonzero by nonzero”);
 }

步驟8:添加命令評估程序

轉到文件中的注釋步驟8,并添加這些行以創(chuàng)建一個switch語句空另,用于評估應用程序用戶可能輸入的命令盆耽。

     switch ( args[0].ToCharArray()[1] ) {
     case ‘r’: PopulateByRow(cplex, var, rng);
               break;
     case ‘c’: PopulateByColumn(cplex, var, rng);
               break;
     case ‘n’: PopulateByNonzero(cplex, var, rng);
               break;
     default:  Usage();
               return;
     }

求解

添加解決問題的應用程序部分。

在聲明決策變量并將約束和目標函數添加到模型后,您的應用程序就可以搜索解決方案了摄杂。

第9步:搜索解決方案

轉到文件中的步驟9坝咐,然后添加此行以使應用程序搜索解決方案。

     if ( cplex.Solve() ) {

第10步:顯示解決方案

轉到文件中的注釋步驟10析恢,并添加這些行以使您的應用程序能夠顯示在步驟9中找到的任何解決方案墨坚。

        double[] x     = cplex.GetValues(var[0]);
        double[] dj    = cplex.GetReducedCosts(var[0]);
        double[] pi    = cplex.GetDuals(rng[0]);
        double[] slack = cplex.GetSlacks(rng[0]);
      
        cplex.Output().WriteLine(“Solution status = “ 
                                 + cplex.GetStatus());
        cplex.Output().WriteLine(“Solution value  = “ 
                                 + cplex.ObjValue);
      
        int nvars = x.Length;
        for (int j = 0; j < nvars; ++j) {
           cplex.Output().WriteLine(“Variable  :” 
                                     + j 
                                     +” Value = “ 
                                     + x[j] 
                                     +” Reduced cost = “ 
                                     + dj[j]);
        }
      
        int ncons = slack.Length;
        for (int i = 0; i < ncons; ++i) {
           cplex.Output().WriteLine(“Constraint:” 
                                     + i 
                                     +” Slack = “ 
                                     + slack[i] 
                                     +” Pi = “ 
                                     + pi[i]);
        }
     }

步驟11:將模型保存到文件中

如果要將模型保存為LP格式的文件,請轉到應用程序文件中的注釋步驟11映挂,然后添加此行泽篮。

     cplex.ExportModel(“l(fā)pex1.lp”);

如果您以交互方式執(zhí)行本教程中的步驟,那么現在您可以編譯并執(zhí)行完整的應用程序柑船。

完整程序

// --------------------------------------------------------------------------
// File: LPex1.cs
// Version 12.9.0
// --------------------------------------------------------------------------
// Licensed Materials - Property of IBM
// 5725-A06 5725-A29 5724-Y48 5724-Y49 5724-Y54 5724-Y55 5655-Y21
// Copyright IBM Corporation 2003, 2019. All Rights Reserved.
//
// US Government Users Restricted Rights - Use, duplication or
// disclosure restricted by GSA ADP Schedule Contract with
// IBM Corp.
// --------------------------------------------------------------------------
//
// LPex1.cs - Entering and optimizing an LP problem
//
// Demonstrates different methods for creating a problem.  The user has to
// choose the method on the command line:
//
//    LPex1  -r     generates the problem by adding constraints
//    LPex1  -c     generates the problem by adding variables
//    LPex1  -n     generates the problem by adding expressions
//

using ILOG.Concert;
using ILOG.CPLEX;


public class LPex1 {
   internal static void Usage() {
      System.Console.WriteLine("usage:   LPex1 <option>");
      System.Console.WriteLine("options:       -r   build model row by row");
      System.Console.WriteLine("options:       -c   build model column by column");
      System.Console.WriteLine("options:       -n   build model nonzero by nonzero");
   }

   public static void Main(string[] args) {
      if ( args.Length != 1 || args[0].ToCharArray()[0] != '-' ) {
         Usage();
         return;
      }

      try {
         // Create the modeler/solver object
         Cplex cplex = new Cplex();

     INumVar[][] var = new INumVar[1][];
     IRange[][]  rng = new IRange[1][];

     // Evaluate command line option and call appropriate populate method.
     // The created ranges and variables are returned as element 0 of arrays
     // var and rng.
     switch ( args[0].ToCharArray()[1] ) {
     case 'r': PopulateByRow(cplex, var, rng);
               break;
     case 'c': PopulateByColumn(cplex, var, rng);
               break;
     case 'n': PopulateByNonzero(cplex, var, rng);
               break;
     default:  Usage();
               return;
     }

     // write model to file
     cplex.ExportModel("lpex1.lp");

     // solve the model and display the solution if one was found
     if ( cplex.Solve() ) {
        double[] x     = cplex.GetValues(var[0]);
        double[] dj    = cplex.GetReducedCosts(var[0]);
        double[] pi    = cplex.GetDuals(rng[0]);
        double[] slack = cplex.GetSlacks(rng[0]);

        cplex.Output().WriteLine("Solution status = " + cplex.GetStatus());
        cplex.Output().WriteLine("Solution value  = " + cplex.ObjValue);

        int nvars = x.Length;
        for (int j = 0; j < nvars; ++j) {
           cplex.Output().WriteLine("Variable   " + j +
                                    ": Value = " + x[j] +
                                    " Reduced cost = " + dj[j]);
        }

        int ncons = slack.Length;
        for (int i = 0; i < ncons; ++i) {
           cplex.Output().WriteLine("Constraint " + i +
                                    ": Slack = " + slack[i] +
                                    " Pi = " + pi[i]);
        }
     }
     cplex.End();
  }
  catch (ILOG.Concert.Exception e) {
     System.Console.WriteLine("Concert exception '" + e + "' caught");
  }

}

   // The following methods all populate the problem with data for the following
   // linear program:
   //
   //    Maximize
   //     x1 + 2 x2 + 3 x3
   //    Subject To
   //     - x1 + x2 + x3 <= 20
   //     x1 - 3 x2 + x3 <= 30
   //    Bounds
   //     0 <= x1 <= 40
   //    End
   //
   // using the IMPModeler API

   internal static void PopulateByRow(IMPModeler model,
                                      INumVar[][] var,
                                      IRange[][] rng) {
      double[]  lb      = {0.0, 0.0, 0.0};
      double[]  ub      = {40.0, double.MaxValue, double.MaxValue};
      string[]  varname = {"x1", "x2", "x3"};
      INumVar[] x       = model.NumVarArray(3, lb, ub, varname);
      var[0] = x;

      double[] objvals = {1.0, 2.0, 3.0};
      model.AddMaximize(model.ScalProd(x, objvals));

      rng[0] = new IRange[2];
      rng[0][0] = model.AddLe(model.Sum(model.Prod(-1.0, x[0]),
                                        model.Prod( 1.0, x[1]),
                                        model.Prod( 1.0, x[2])), 20.0, "c1");
      rng[0][1] = model.AddLe(model.Sum(model.Prod( 1.0, x[0]),
                                        model.Prod(-3.0, x[1]),
                                        model.Prod( 1.0, x[2])), 30.0, "c2");
   }

   internal static void PopulateByColumn(IMPModeler model,
                                         INumVar[][] var,
                                         IRange[][] rng) {
      IObjective obj = model.AddMaximize();

      rng[0] = new IRange[2];
      rng[0][0] = model.AddRange(-double.MaxValue, 20.0, "c1");
      rng[0][1] = model.AddRange(-double.MaxValue, 30.0, "c2");

      IRange r0 = rng[0][0];
      IRange r1 = rng[0][1];

      var[0] = new INumVar[3];
      var[0][0] = model.NumVar(model.Column(obj,  1.0).And(
                               model.Column(r0,  -1.0).And(
                               model.Column(r1,   1.0))),
                               0.0, 40.0, "x1");
      var[0][1] = model.NumVar(model.Column(obj,  2.0).And(
                               model.Column(r0,   1.0).And(
                               model.Column(r1,  -3.0))),
                               0.0, double.MaxValue, "x2");
      var[0][2] = model.NumVar(model.Column(obj,  3.0).And(
                              model.Column(r0,   1.0).And(
                               model.Column(r1,   1.0))),
                               0.0, double.MaxValue, "x3");
   }

   internal static void PopulateByNonzero(IMPModeler model,
                                          INumVar[][] var,
                                          IRange[][] rng) {
      double[]  lb = {0.0, 0.0, 0.0};
      double[]  ub = {40.0, double.MaxValue, double.MaxValue};
      INumVar[] x  = model.NumVarArray(3, lb, ub);
      var[0] = x;

      double[] objvals = {1.0, 2.0, 3.0};
      model.Add(model.Maximize(model.ScalProd(x, objvals)));

      rng[0] = new IRange[2];
      rng[0][0] = model.AddRange(-double.MaxValue, 20.0);
      rng[0][1] = model.AddRange(-double.MaxValue, 30.0);

      rng[0][0].Expr = model.Sum(model.Prod(-1.0, x[0]),
                                 model.Prod( 1.0, x[1]),
                                 model.Prod( 1.0, x[2]));
      rng[0][1].Expr = model.Sum(model.Prod( 1.0, x[0]),
                                 model.Prod(-3.0, x[1]),
                                 model.Prod( 1.0, x[2]));
      x[0].Name = "x1";
      x[1].Name = "x2";
      x[2].Name = "x3";

      rng[0][0].Name = "c1";
      rng[0][0].Name = "c2";
   }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末帽撑,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子鞍时,更是在濱河造成了極大的恐慌亏拉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逆巍,死亡現場離奇詭異及塘,居然都是意外死亡,警方通過查閱死者的電腦和手機锐极,發(fā)現死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門笙僚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人灵再,你說我怎么就攤上這事肋层。” “怎么了翎迁?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵槽驶,是天一觀的道長。 經常有香客問我鸳兽,道長掂铐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任揍异,我火速辦了婚禮全陨,結果婚禮上,老公的妹妹穿的比我還像新娘衷掷。我一直安慰自己辱姨,他們只是感情好,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布戚嗅。 她就那樣靜靜地躺著雨涛,像睡著了一般枢舶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上替久,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天凉泄,我揣著相機與錄音,去河邊找鬼蚯根。 笑死后众,一個胖子當著我的面吹牛,可吹牛的內容都是我干的颅拦。 我是一名探鬼主播蒂誉,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼距帅!你這毒婦竟也來了右锨?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤碌秸,失蹤者是張志新(化名)和其女友劉穎陡蝇,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體哮肚,經...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年广匙,在試婚紗的時候發(fā)現自己被綠了允趟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸦致,死狀恐怖潮剪,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情分唾,我是刑警寧澤抗碰,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站绽乔,受9級特大地震影響弧蝇,放射性物質發(fā)生泄漏。R本人自食惡果不足惜折砸,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一看疗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧睦授,春花似錦两芳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽是复。三九已至,卻和暖如春竖螃,著一層夾襖步出監(jiān)牢的瞬間淑廊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工斑鼻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蒋纬,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓坚弱,卻偏偏與公主長得像蜀备,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子荒叶,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354