POJ3169 差分約束系統 解題報告

【問題描述】  
  
  如果一個系統由n個變量和m個約束條件組成,其中每個約束條件形如xj-xi≤bk(i,j∈[1,n],k∈[1,m]),則稱其爲差分約束系統。亦即,差分約束系統是求解關於一組變量的特殊不等式組的方法。 


  下面是關於差分約束系統一個實際問題的描述: 


  FJ有 n 頭奶牛(編號從 1 到 n),沿一條直線站着等候餵食,由於奶牛們身材都比較苗條,所以可能有多頭奶牛站在同一個位置的情況。設第i頭奶牛站隊位置爲d[i],在安排每頭奶牛站隊位置d[i]時需要滿足如下的條件:
  1、奶牛應按照編號順序站隊,即d[i]-d[i+1]<=0。
  2、m對友好的牛希望彼此站的近些。即對於友好關係(i,j,D)有d[j]-d[i]≤D(1 ≤ i < j ≤ n)。
  3、p對敵對的牛希望彼此站的遠些。即對於敵對關係(i,j,L)有d[j]-d[i]≥L(1 ≤ i < j ≤ n)。


  現在請你幫助FJ判斷是否存在滿足這些條件的一種站隊方案,如果存在請計算1號奶牛與n號奶牛之間的最大距離。如果不存在滿足要求的方案,輸出-1;如果1號奶牛和N號奶牛間的距離可以任意大,輸出-2; 
 
    
 【輸入格式】  
  
  第 1 行輸入 n,m,p,接下來的 m 行,每行三個整數 i,j,D,表示牛 i 和牛 j 的距離最多爲 D,再接下來的 p 行,每行三個整數 i,j,L,表示牛 i 和牛 j 的距離最少爲 L。
 
    
 【輸出格式】  
   
  如果不存在滿足要求的方案,輸出-1;如果1號奶牛和N號奶牛間的距離可以任意大,輸出-2;否則,計算出在滿足所有要求的情況下,1 號奶牛和 N 號奶牛間可能的最大距離。
 
    
 【輸入樣例】   
   
4 2 1
1 3 10
2 4 20
2 3 3
 
    
 【輸出樣例】  
   
27
 
    
 【樣例解釋】  
   
四隻奶牛的位置分別爲:0,7,10,27
 
    
 【數據範圍】  
   
2≤n≤1000  ,  1≤m,p≤10000  , 1≤D,L≤1000000
 
    
 【來源】  
  
poj3169


 解題思路:根據題意,求差分約束系統的方法,就是將所給的信息,轉化爲圖,通過求最優路徑達到目的。那麼,怎麼將輸入的信息有效地轉化爲圖呢(重點,難點)?看到這麼多個不等式,不難想到求最短路徑時的三角圖的不等式——d[j]<=d[i]+c,將不等式變一下形可以得到d[j]-d[i]<=c,此時從i出發連了一條有向邊到j,同理,將題中所給的不等式變形成與上式一樣的形式,可以得到d[i]-d[i+1]<=0,d[j]-d[i]<=D,d[i]-d[j]<=-L,將這些不等式與上式類比,則可以看成i+1到i連了一條邊權爲0的有向邊,i到j連了一條邊權爲D的有向邊,j到i連了一條邊權爲-L的有向邊,至此,圖被我們建立了起來,問題由兩頭奶牛間的最大距離轉化爲求圖上兩點的最短路徑(這裏解釋一下爲什麼求的是最短路徑,因爲根據三角圖關係d[j]<=d[i]+c,說明在滿足條件的情況下,d[j]最大可以取到d[i]+c)。需要注意的是,這裏要判斷是否存在滿足要求的方案及奶牛間的距離是否可以無限大,如果圖中存在負權迴路,則說明沒有滿足要求的方案,如果計算完最短路徑後d[N]的值仍爲初始時的無窮大,則說明奶牛間的距離可以無限大。


#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1005;
const int inf=1000000010;
int n,m,p,a,b,D,L;
vector<int>g[maxn],w[maxn];
int d[maxn],inq[maxn],num[maxn];
int SPFA(int s)  //SPFA算法計算最短路徑並判斷是否有負權迴路
{
	queue<int>q;
	for(int i=1;i<=n;i++)
	d[i]=inf;
	memset(inq,0,sizeof(inq));
	memset(num,0,sizeof(num));
	q.push(s);
	inq[s]=1;
	num[s]++;
	d[s]=0;
	while(!q.empty())
	{
		int i=q.front();  q.pop();
		inq[i]=0;
		for(int k=0;k<g[i].size();k++)
		{
			int j=g[i][k],c=w[i][k];
			if(d[i]+c<d[j])
			{
				d[j]=d[i]+c;
				num[j]++;
				if(num[j]==n)  
				{
					return 0;  //存在負權迴路
				}
				if(inq[j]==0)
				{
					q.push(j);
					inq[j]=1;
				}
			}
		}
	}
	return 1;
}
int main()
{	
	freopen("48.in","r",stdin);
	//freopen("48.out","w",stdout);
	scanf("%d%d%d",&n,&m,&p);
	for(int i=1;i<n;i++)   //d[i]-d[i+1]<=0
	{
		g[i+1].push_back(i);
		w[i+1].push_back(0);
	}
	for(int i=1;i<=m;i++)  //d[b]-d[a]<=D
	{
		scanf("%d%d%d",&a,&b,&D);
		g[a].push_back(b);
		w[a].push_back(D);
	}
	for(int i=1;i<=p;i++)  //d[a]-d[b]<=-L
	{
		scanf("%d%d%d",&a,&b,&L);
		g[b].push_back(a);
		w[b].push_back(-L);
	}
	if(SPFA(1)==0)  
	{
		printf("-1\n");
	}
	if(SPFA(1)==1)  
	{
		if(d[n]==inf)  printf("-2\n");  //奶牛間的距離可以無限大
		else  printf("%d\n",d[n]);
	}
	return 0;
}


發佈了57 篇原創文章 · 獲贊 8 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章