推荐几个比较好的博客:https://blog.csdn.net/whereisherofrom/article/details/78922648 最短路和差分约束
http://www.cnblogs.com/void/archive/2011/08/26/2153928.html 差分约数系统详解
https://blog.csdn.net/xuezhongfenfei/article/details/8685313 差分约束系统
SPFA最短路模板:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=1010; 8 const int inf=1e9; 9 struct edge{ 10 int v,cost; 11 edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 12 }; 13 vector<edge>E[maxn]; 14 bool vis[maxn]; 15 int cnt[maxn],dist[maxn],s,n; 16 17 void addedge(int u,int v,int w) 18 { 19 E[u].push_back(edge(v,w)); 20 } 21 22 bool SPFA() 23 { 24 memset(vis,false,sizeof(vis)); 25 memset(cnt,0,sizeof(cnt)); 26 for ( int i=1;i<=n;i++ ) dist[i]=inf; 27 vis[s]=true; 28 dist[s]=0; 29 queue<int>que; 30 que.push(s); 31 cnt[s]=1; 32 while ( !que.empty() ) { 33 int u=que.front(); 34 que.pop(); 35 vis[u]=false; 36 for ( int i=0;i<E[u].size();i++ ) { 37 int v=E[u][i].v; 38 int cost=E[u][i].cost; 39 if ( dist[v]>dist[u]+cost ) { 40 dist[v]=dist[u]+cost; 41 if ( !vis[v] ) { 42 vis[v]=true; 43 que.push(v); 44 if ( ++cnt[v]>n ) return false; 45 } 46 } 47 } 48 } 49 return true; 50 }
最长路模板:即将边权取负,最后的结果取负即可
1.(HDOJ1384)http://acm.hdu.edu.cn/showproblem.php?pid=1384
题意:有n个区间,给出每个区间的左端点和右端点以及在该区间至少有多少个数在集合Z里面,现在让你求出集合Z里面最少元素个数。
分析:首先该问题是求最少的元素个数所以需要求最长路,所有不等式的符号都是>=。对于d[i]表示从[0,i]中至少有多少元素在Z中。所以给定[x,y]和z,有d[y]-d[x-1]>=z,因为数组下标可以为0,所有将整个坐标向右平移一位(即坐标都+1).注意隐藏条件对于每个位置来说最多有一个元素,最少没有元素(即:d[i]-d[i-1]>=0 && d[i]-d[i-1]<=1)。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=1010; 8 const int inf=1e9; 9 struct edge{ 10 int v,cost; 11 edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 12 }; 13 vector<edge>E[maxn]; 14 bool vis[maxn]; 15 int cnt[maxn],dist[maxn],s,n; 16 17 void addedge(int u,int v,int w) 18 { 19 E[u].push_back(edge(v,w)); 20 } 21 22 bool SPFA() 23 { 24 memset(vis,false,sizeof(vis)); 25 memset(cnt,0,sizeof(cnt)); 26 for ( int i=1;i<=n;i++ ) dist[i]=inf; 27 vis[s]=true; 28 dist[s]=0; 29 queue<int>que; 30 que.push(s); 31 cnt[s]=1; 32 while ( !que.empty() ) { 33 int u=que.front(); 34 que.pop(); 35 vis[u]=false; 36 for ( int i=0;i<E[u].size();i++ ) { 37 int v=E[u][i].v; 38 int cost=E[u][i].cost; 39 if ( dist[v]>dist[u]+cost ) { 40 dist[v]=dist[u]+cost; 41 if ( !vis[v] ) { 42 vis[v]=true; 43 que.push(v); 44 if ( ++cnt[v]>n ) return false; 45 } 46 } 47 } 48 } 49 return true; 50 }
2.(HDOJ1531)http://acm.hdu.edu.cn/showproblem.php?pid=1531
题意: 问是否存在长度为n的序列满足m个条件. 每个条件描述某一段子序列和大于或者小于k。注意条件的表示si,ni为si到si+ni这个范围
分析:用最长路处理,设置超级源点n+1(注意一共有n+2个点,包括初始化和判断一个点的入队都要用n+2,而不是n来判断)。除了给定m个条件外,还需要将超级源点连向其他点,建边权为0的边
注意:对于>和<的处理,是先变形(即改变不等号的方向)在变成>=或者<=。同时注意建边的方向,是谁指向谁,边权是多少。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=110; 8 const int inf=1e9; 9 struct edge{ 10 int v,cost; 11 edge(int _v=0,int _cost=0):v(_v),cost(_cost) {} 12 }; 13 vector<edge>E[maxn]; 14 bool vis[maxn]; 15 int cnt[maxn],dist[maxn],s,n; 16 17 void addedge(int u,int v,int w) 18 { 19 E[u].push_back(edge(v,-w)); 20 } 21 22 bool SPFA() 23 { 24 memset(vis,false,sizeof(vis)); 25 memset(cnt,0,sizeof(cnt)); 26 for ( int i=0;i<=n+1;i++ ) dist[i]=inf; 27 vis[s]=true; 28 dist[s]=0; 29 queue<int>que; 30 que.push(s); 31 cnt[s]=1; 32 while ( !que.empty() ) { 33 int u=que.front(); 34 que.pop(); 35 vis[u]=false; 36 for ( int i=0;i<E[u].size();i++ ) { 37 int v=E[u][i].v; 38 int cost=E[u][i].cost; 39 if ( dist[v]>dist[u]+cost ) { 40 dist[v]=dist[u]+cost; 41 if ( !vis[v] ) { 42 vis[v]=true; 43 que.push(v); 44 if ( ++cnt[v]>n+2 ) return false; 45 } 46 } 47 } 48 } 49 return true; 50 } 51 52 int main() 53 { 54 int m,i,j,k,x,y,z; 55 char str[10]; 56 bool flag; 57 while ( scanf("%d",&n)!=EOF && n ) { 58 scanf("%d",&m); 59 for ( i=0;i<=n+1;i++ ) E[i].clear(); 60 while ( m-- ) { 61 scanf("%d%d%s%d",&x,&y,str,&z); 62 y+=x; 63 x--; 64 if ( str[0]=='g' ) addedge(x,y,z+1); 65 else if ( str[0]=='l' ) addedge(y,x,-z+1); 66 } 67 s=n+1; 68 for ( i=0;i<=n;i++ ) { 69 addedge(s,i,0); 70 } 71 flag=SPFA(); 72 if ( flag ) printf("lamentable kingdom\n"); 73 else printf("successful conspiracy\n"); 74 } 75 return 0; 76 }