1. 程式人生 > >POJ 3159 Candies(差分約束+spfa+鏈式前向星)

POJ 3159 Candies(差分約束+spfa+鏈式前向星)

void tdi div con pre ace != view ash

題目鏈接:http://poj.org/problem?id=3159

題目大意:給n個人派糖果,給出m組數據,每組數據包含A,B,C三個數,意思是A的糖果數比B少的個數不多於C,即B的糖果數 - A的糖果數<=C 。

最後求n 比 1 最多多多少顆糖果。

解題思路:經典差分約束的題目,具體證明看這裏《數與圖的完美結合——淺析差分約束系統》。

不妨將糖果數當作距離,把相差的最大糖果數看成有向邊AB的權值,我們得到 dis[B]-dis[A]<=w(A,B)。看到這裏,我們可以聯想到求最短路時的松弛操作,

當if(dis[B]>dis[A]+w(A,B)因為要使A,B間滿足dis[B]-dis[A]<=w(A,B)右要使差值最大,所以dis[B]=dis[A]+w(A,B)。

所以這題可以轉化為最短路來求。註意:很坑,這題的spfa被卡了,要用棧才不會超時。

代碼:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<stack>
 7 using namespace std;
 8 const int N=2e5+5;
 9 
10 struct node{
11     int to,next,w;
12 }edge[N]; 13 14 int n,m; 15 int idx,head[N]; 16 //初始化 17 void init(){ 18 idx=1; 19 memset(head,-1,sizeof(head)); 20 } 21 //添加邊 22 void addEdge(int u,int v,int w){ 23 edge[idx].to=v; 24 edge[idx].w=w; 25 edge[idx].next=head[u]; 26 head[u]=idx; 27 idx++; 28
} 29 30 int dis[N]; 31 bool vis[N]; 32 void spfa(int s){ 33 memset(dis,0x3f,sizeof(dis)); 34 dis[s]=0; 35 stack<int>sk; 36 sk.push(s); 37 while(!sk.empty()){ 38 int k=sk.top(); 39 sk.pop(); 40 vis[k]=false; 41 for(int i=head[k];i!=-1;i=edge[i].next){ 42 node t=edge[i]; 43 //改變了松弛條件 44 if(dis[t.to]>dis[k]+t.w){ 45 dis[t.to]=dis[k]+t.w; 46 if(!vis[t.to]){ 47 sk.push(t.to); 48 vis[t.to]=true; 49 } 50 } 51 } 52 } 53 } 54 55 int main(){ 56 init(); 57 scanf("%d%d",&n,&m); 58 for(int i=1;i<=m;i++){ 59 int a,b,w; 60 scanf("%d%d%d",&a,&b,&w); 61 addEdge(a,b,w); 62 } 63 spfa(1); 64 printf("%d\n",dis[n]-dis[1]); 65 return 0; 66 }

POJ 3159 Candies(差分約束+spfa+鏈式前向星)