第一次做差分約束的題,和zzy神牛一起做的,今天的目標還是3題,這是第一題。
差分約束就是有N個點M個約束條件,去尋找所需要的東西。可以用SPFA也可以用BellmanFord,但是這個題的問題在於沒有原點,於是乎~
1.>建立一個超級原點,該原點到所有的店的距離都是0,將所有點都入隊,再通過SPFA去尋找最短路徑。如果說從超級原點到任何點的距離變成了負數,也就是說存在一個負環,這樣便會進入死迴圈。輸出無解。
2.>將所有點都入隊,標記。當隊首元素為INF時,將其修改為0,作為原點。這樣可以存在多個原點。最後,使用一個cnt數組來標記每個點入隊的次數,若大於N-1即頂點數-1,則出現死迴圈,輸出無解。
另外構圖呢~~~
i->j=p i點到j的值為p.放置在圖中也就是
i->j>=p;i->j<=p;
dist[j]<=dist[i]+p;dist[j]>=dist[i]+p;
=>dist[j]<=dist[i]+p;
dist[i]<=dist[j]-p;
也就是i->j有為p的路徑 j->i有為-p的路徑。
這樣構圖就ok了~ 然後就開始裸了
#include<iostream>#include<queue>#define MAXN 1001#define MAXM 100001#define INF 0x7F7F7F7Fusing namespace std;struct node{ int v; int price; node *next;}edge[2][MAXM],*ptr[MAXN];int dist[MAXN];int N,M;bool spfa(){ bool used[MAXN]; int cnt[MAXN]; memset( dist,0x7F,sizeof(dist) ); memset( used,1,sizeof(used) ); memset( cnt,0,sizeof(cnt) ); int i,j,k; queue<int>myQueue; while( !myQueue.empty() )myQueue.pop(); for( i=1;i<=N;i++ )myQueue.push(i); int u; while( !myQueue.empty() ) { u=myQueue.front();myQueue.pop(); if( dist[u]==INF ) dist[u]=0; node *p=ptr[u]; used[u]=false; while( p ) { if( dist[p->v]>dist[u]+p->price ) { dist[p->v]=dist[u]+p->price; if( !used[p->v] ) { myQueue.push(p->v); used[p->v]=true; if( ++cnt[u]>N-1 ) return false; } } p=p->next; } } return true;}int main(){ char com; int i,j,k; while( scanf("%d %d",&N,&M )!=EOF ) { int u,v,val; for( i=1;i<=N;i++ ) ptr[i]=NULL; for( i=1;i<=M;i++ ) { scanf( "\n%c %d %d",&com,&u,&v ); if( com=='P' ) { scanf( "%d",&val ); node *p=&edge[0][i]; p->v=v; p->price=val; p->next=ptr[u]; ptr[u]=p; p=&edge[1][i]; p->v=u; p->price=-val; p->next=ptr[v]; ptr[v]=p; } else { node *p=&edge[0][i]; p->v=u; p->price=-1; p->next=ptr[v]; ptr[v]=p; } } if( spfa() ) printf( "Reliable\n" ); else printf( "Unreliable\n" ); } return 0; }