POJ3159_Candies_差分約束_SPFA

/*

吐槽

這道題又是自己沒好好想就去網上查題解去了- -發現是一道差分約束的題,以前沒聽說過這個啊-  -沒辦法就去百科了一下什麼是差分約束,發現是轉化成最短路徑來解。

然後看題解上說都是最短路徑,自己以爲是最長路,很是鬱悶- -後來自己推了推,算是半懂不懂的理解了把。

本來計劃直接做呢,但是發現大家說用隊列會超時,必須得用棧- -沒有用過啊!!看了代碼發現除了定義不一樣,其他幾乎一樣的,這樣,棧,隊列,優先隊列三種都做過至少一次了,形式都很像。

後悔查代碼了,如果自己做的話肯定會用隊列,然後TLE一次才印象深刻,這樣看別人題解規避自己可能犯的錯誤感覺心裏很彆扭- -

(Ps:剛剛親測一遍,就是把定義改一下,然後Q.pop()改成Q.front()就好了,果然TLE- -,不過心裏舒坦了一些)

唉,總之昨天沒做完,晚上去看09視頻了,這幾天效率太低,被同學拉下一週的內容了,要好好加把勁才行啊

*/

題意

        從1到N,N個點之間有關係,A,B,c代表A不能忍受B能比他多 超過c個糖果,也就是B<=A+c,給出這些關係,讓你求N最多能比1多多少個糖果

思路:

          然後把這些關係轉化成一個圖,用最短路徑解,原理與步驟詳見百度百科差分約束詞條//具體於本題的轉化思路在代碼的註釋裏

/*

         如果一個系統由n個變量和m個約束條件組成,其中每個約束條件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),則稱其爲差分約束系統(system of difference constraints)。亦即,差分約束系統是求解關於一組變量的特殊不等式組的方法。
         求解差分約束系統,可以轉化成圖論的單源最短路徑(或最長路徑)問題。
觀察xj-xi<=bk,會發現它類似最短路中的三角不等式d[v]<=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。因此,以每個變量xi爲結點,對於約束條件xj-xi<=bk,連接一條邊(i,j),邊權爲bk。我們再增加一個源點s,s與所有定點相連,邊權均爲0。對這個圖,以s爲源點運行Bellman-ford算法(或SPFA算法),最終{d[ i]}即爲一組可行解。

轉載於百度百科http://baike.baidu.com/view/1008149.htm

*/



原題:

Candies
Time Limit: 1500MS   Memory Limit: 131072K
Total Submissions: 20216   Accepted: 5346

Description

During the kindergarten days, flymouse was the monitor of his class. Occasionally the head-teacher brought the kids of flymouse’s class a large bag of candies and had flymouse distribute them. All the kids loved candies very much and often compared the numbers of candies they got with others. A kid A could had the idea that though it might be the case that another kid B was better than him in some aspect and therefore had a reason for deserving more candies than he did, he should never get a certain number of candies fewer than B did no matter how many candies he actually got, otherwise he would feel dissatisfied and go to the head-teacher to complain about flymouse’s biased distribution.

snoopy shared class with flymouse at that time. flymouse always compared the number of his candies with that of snoopy’s. He wanted to make the difference between the numbers as large as possible while keeping every kid satisfied. Now he had just got another bag of candies from the head-teacher, what was the largest difference he could make out of it?

Input

The input contains a single test cases. The test cases starts with a line with two integersN and M not exceeding 30 000 and 150 000 respectively. N is the number of kids in the class and the kids were numbered 1 throughN. snoopy and flymouse were always numbered 1 and N. Then followM lines each holding three integers A, B and c in order, meaning that kidA believed that kid B should never get over c candies more than he did.

Output

Output one line with only the largest difference desired. The difference is guaranteed to be finite.

Sample Input

2 2
1 2 5
2 1 4

Sample Output

5

Run ID User Problem Result Memory Time Language Code Length Submit Time
11761910 chengtbf 3159 Accepted 2112K 688MS C++ 1706B 2013-07-11 09:15:17


代碼:


/*
剛開始以爲是轉化成最長路,因爲題中是求最大差值嘛,但是網上一看都是最短路,十分困惑,就自己推一下
輸入是A->B(c),建立有向邊,表示B<=A+c才成立,即A>=B+(-c)才成立。要求最大的差值N-1,即1-N的絕對值最大。
所以有方程if(A<B+(-c))A=B+(-c),讓差值儘可能大。如果A>B+(-c),那本身就滿足條件,不需要鬆弛
上面的鬆弛條件轉化一下就是if(B>A+c)B=A+c;
其實這裏並不是嚴格的最短路徑,因爲狀態鬆弛的條件跟正常的最短路徑是反的,因爲正常的有向邊是if(A>B+C)A=B+c;而這裏A、B相反,
所以其實是用最短路徑的模版求最大差值


初始化自己剛開始也沒想好,但是現在推一遍感覺有點眉目了,2到N初始化爲MAXN,
表示假設剛開始差了無窮大(顯然實際是不可能的),但是找其中滿足情況的最小路徑,就是找滿足條件的最大差值

*/

#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
#define MAXN 2000000000//悲催啊,題中沒給差值的範圍- -所以儘量開大點,到20億
using namespace std;

typedef struct MyStruct
{
	int to,next,val;
}EDGE;

EDGE edge[150010];//邊數組
int head[30010];
int dis[30010];//存點1到點i允許的最大差值
int count_num;
int flag[30010];//標記數組標記是否在棧中
stack<int>Q;
void addedge(int a,int b,int w)
{
	edge[count_num].to=b;
	edge[count_num].next=head[a];
	edge[count_num].val=w;
	head[a]=count_num++;
}

void SPFA()
{
	while (!Q.empty())
	{
		Q.pop();
	}
	int temp,son,i;
	Q.push(1);
	while (!Q.empty())
	{
		temp=Q.top();
		flag[temp]=0;
		Q.pop();
		for ( i = head[temp]; i !=-1; i=edge[i].next)
		{
			son=edge[i].to;
			if (dis[son]>dis[temp]+edge[i].val)
			{
				dis[son]=dis[temp]+edge[i].val;
				if (flag[son]==0)
				{
					Q.push(son);
					flag[son]=1;
				}
			}
		}
	}
}

int main()
{
	int a,b,w,n,m,i;
	while (scanf("%d%d",&n,&m)!=EOF)
	{
		count_num=1;//初始化
		dis[1]=0;
		memset(flag,0,sizeof(flag));
		memset(head,-1,sizeof(head));
		for ( i = 2; i <=n ; i++)
		{
			dis[i]=MAXN;
		}
		//輸入
		for ( i = 1; i <=m ; i++)
		{
			scanf("%d%d%d",&a,&b,&w);
			addedge(a,b,w);
		}
		//處理
		SPFA();
		//輸出
		printf("%d\n",dis[n]);
	}
	return 0;
}




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