程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 差分約束系統C++實現

差分約束系統C++實現

編輯:C++入門知識

 

差分約束:線性規劃矩陣A的每一行包含一個1與一個-1,其他元素為0.因此,由Ax<=b給出的約束條件是m個差分約束集合,其中包含n個未知元。每個約束條件為不等式:

                                                            xj-xi<=bk

其中1<=i,j<=n,i<=k<=m

 

解決方法:把n個未知元看成n的有向圖的頂點,xj-xi<=bk表示頂點j到頂點i長度為bk的有向線段。再添加一個v0頂點,與v0到其余頂點的有向線段,長度為0。(如下圖)

可以證明xi=β(v0,vi)(β(v0,vi)為頂點0到頂點i的最短路徑長度)。所以就可以利用Bellman_Ford算求單源最短路徑(不能用Dijkstra算法,因為有向線段長度可以為負)

// 差分約束系統.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include<iostream>

#define MAX 100

#define Infinity 65535

using namespace std;

//邊的尾節點結構體

struct edgeNode

{

 int no; //邊尾端的序號

 int weight; //邊權值

 struct edgeNode * next; //下一個

};

//節點結構體

struct vexNode

{

 char info;  //節點名稱

 struct edgeNode *link; //與之相連的端點

};

//存儲節點信息

vexNode adjlist[MAX];

//前驅節點

int parent[MAX];

////源點到節點j最短路徑的花費

int lowcost[MAX];

//差分矩陣

int  a[MAX][MAX];

//約束集

int w[MAX];

//根據差分矩陣建立鄰接表存儲

//adjlist為節點集,parent[j]為從0節點到節點j的最短路徑的前驅節點

//lowcost[j]為從0節點到節點j的最短路徑的代價

//w為輸入的差分約束

//m,n分別為差分矩陣的行數和列數

void createGraph(vexNode *adjlist,int *parent,int *lowcost,int *w,int m,int n)

{

 int i,j;

 //初始化,節點vi的名稱為char(a+i)

 for(i=0;i<=n;i++)

 {

  adjlist[i].info = (char)('a' + i);

  adjlist[i].link = NULL;

  lowcost[i] = Infinity;

  parent[i] = i;

 }

 int col1,col2;

 col1 = col2 = 0;

 edgeNode *p1;

 for(i=1;i<=m;i++)

 {

  for(j=1;j<=n;j++)

  {

   if(a[i][j]==-1)

    col1 = j;

   else if(a[i][j]==1)

    col2 = j;

  }

  p1 = (edgeNode*)malloc(sizeof(edgeNode));

  p1->no = col2;

  p1->weight = w[i];

  p1->next = adjlist[col1].link;

  adjlist[col1].link = p1;

 }

 for(i=1;i<=n;i++)

 {

  p1 = (edgeNode*)malloc(sizeof(edgeNode));

  p1->no = i;

  p1->weight = 0;

  p1->next = adjlist[0].link;

  adjlist[0].link = p1;

 }

 lowcost[0] = 0;

}

//尋找v0到,每一個節點的最短路徑

bool Bellman_Ford(vexNode *adjlist,int *lowcost,int *parent,const int n)

{

 int i,j;

 for(j=0;j<n;j++)

 {

  for(i=0;i<=n;i++)

  {

   edgeNode *p1 = adjlist[i].link;

   while(p1 != NULL)

   {

    if(lowcost[i]+p1->weight <lowcost[p1->no])

    {

     lowcost[p1->no] = lowcost[i]+p1->weight;

     parent[p1->no] = i;

    }

    p1 = p1->next;

   }

  }

 }

 //檢查有無負回路

  for(i=1;i<=n;i++)

  {

   edgeNode *p2 = adjlist[i].link;

   while(p2 != NULL)

   {

    if(lowcost[p2->no]>lowcost[i]+p2->weight)

     return false;

    p2 = p2->next;

   }

  }

 return true;

}

 

int _tmain(int argc, _TCHAR* argv[])

{

 int cases;

 cout<<"請輸入案例的個數:";

 cin>>cases;

 while(cases--)

 {

  int i,j;

  int n,m;

  cout<<"請輸入差分矩陣的行數(m)與列數(n):";

  cin>>m>>n;

  cout<<"請輸入差分矩陣:"<<endl;

  for(i=1;i<=m;i++)

   for(j=1;j<=n;j++)

    cin>>a[i][j];

  cout<<"請輸入約束集:"<<endl;

  for(i=1;i<=m;i++)

   cin>>w[i];

  //創建鄰接表

  createGraph(adjlist,parent,lowcost,w,m,n);

  //輸出鄰接表

  /*

  for(i=0;i<=n;i++)

  {

   edgeNode *p = adjlist[i].link;

   cout<<i<<":";

   while(p != NULL)

   {

    cout<<"("<<p->no<<","<<p->weight<<") ";

    p = p->next;

   }

   cout<<endl;

  }

  */

  //調用Bellman-Ford算法

  bool flag = Bellman_Ford(adjlist,lowcost,parent,n);

  if(!flag)

   cout<<"無解"<<endl;

  else

  {

   //輸出解集

   cout<<"其中一個解集為(此解集加上一個任意的常數d也是其解集):"<<endl;

   for(i=1;i<=n;i++)

    cout<<"x"<<i<<"="<<lowcost[i]<<endl;

  }

 }

 system("pause");

 return 0;

}

---------------------------------------------------程序測試---------------------------------------------------       

 

                                \                                      

 

 

\

 

請輸入案例的個數:1

請輸入差分矩陣的行數(m)與列數(n):8  5

請輸入差分矩陣:

1 -1 0 0 0

1 0 0 0 -1

0 1 0 0 -1

-1 0 1 0 0

-1 0 0 1 0

0 0 -1 1 0

0 0 -1 0 1

0 0 0 -1 1

請輸入約束集:

0 -1 1 5 4 -1 -3 -3

其中一個解集為(此解集加上一個任意的常數d也是其解集):

x1=-5

x2=-3

x3=0

x4=-1

x5=-4

請按任意鍵繼續. .

 

作者 heyongluoyao8

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved