题目大意:有N头牛,编号1-N,按编号排成一排准备吃东西,有些牛的关系比较好,所以希望他们不超过一定的距离,也有一些牛的关系很不好,所以希望彼此之间要满足某个关系,牛可以挤在同一个位置上,现在给出N个牛的信息,问你能否实现一种排列方案,使得d[1]到d[N]最大?如果不存在输出-1,无限大输出-2
这一题看上去挺难的,但是如果你知道差分约束原理,这一题似乎还是挺简单的。
差分约束的原理是:存在任意线性方程,满足d[A]+c>=d[B],就可以表示为图的最短路形式,方程可以表示为A->B,权值为c的边,最后任意点之间距离之差的最大值,即为两点之间的最短距离。
在最短路的算法中,恒有d[u]+w>=d[s](s是源点,w是权值,u是除了s的任意点),则d[u]-d[s]的最大值即为s-u的最短路经长。
回到题目上来,那么这一题事实上蕴含了三个线性方程:
1.d[i+1]>=d[i](按照编号排序)
2.d[BL]-d[AL]<=DL->->->d[AL]+DL>=d[BL]
3.d[BD]-D[AD]>=DD->->->d[BD]-DD>=d[AD]
则我们只用把这些边表示出来算最短路径就可以了,这一题有负值边,用Bellman_Ford或者SPFA就可以了
Bellman_Ford:
1 #include <iostream> 2 #include <functional> 3 #include <algorithm> 4 #define MAX 0x7f7f7f7f 5 6 using namespace std; 7 8 typedef int Positon; 9 typedef struct least_ 10 { 11 Positon A; 12 Positon B; 13 int cost; 14 }Relation; 15 16 static Relation L_Set[1000005],M_Set[1000005]; 17 static int dist[1005]; 18 19 void Bellman_Ford(const int, const int, const int); 20 21 int main(void) 22 { 23 int cows_sum, ML, MD; 24 while (~scanf("%d%d%d", &cows_sum, &ML, &MD)) 25 { 26 for (int i = 0; i < ML; i++) 27 scanf("%d%d%d", &L_Set[i].A, &L_Set[i].B, &L_Set[i].cost); 28 for (int i = 0; i < MD; i++) 29 scanf("%d%d%d", &M_Set[i].A, &M_Set[i].B, &M_Set[i].cost); 30 Bellman_Ford(cows_sum, ML, MD); 31 } 32 return 0; 33 } 34 35 void Bellman_Ford(const int cows_sum, const int ML, const int MD) 36 { 37 memset(dist, 0x7f, sizeof(dist)); 38 dist[1] = 0;//到自己肯定是最短的 39 40 for (int i = 1; i <= cows_sum; i++) 41 { 42 for (int i = 1; i + 1 <= cows_sum; i++) 43 if (dist[i + 1] < MAX)//差分约束方程d[i+1]>=d[i] 44 dist[i] = min(dist[i], dist[i + 1]); 45 for (int i = 0; i < ML; i++)//差分约束方程d[AL]+DL>=d[BL] 46 if (dist[L_Set[i].A] < MAX) 47 dist[L_Set[i].B] = min(dist[L_Set[i].B], dist[L_Set[i].A] + L_Set[i].cost); 48 for (int i = 0; i < MD; i++)//差分约束方程d[BD]-DD>=d[AD] 49 if (dist[M_Set[i].B] < MAX) 50 dist[M_Set[i].A] = min(dist[M_Set[i].A], dist[M_Set[i].B] - M_Set[i].cost); 51 } 52 53 int ans = dist[cows_sum]; 54 if (dist[1] < 0) 55 printf("-1 "); 56 else if (dist[cows_sum] == MAX) 57 printf("-2 "); 58 else printf("%d ", ans); 59 }
SPFA:
1 #include <iostream> 2 #include <functional> 3 #include <algorithm> 4 #include <queue> 5 #define MAX 0x7f7f7f7f 6 7 using namespace std; 8 9 typedef int Position; 10 typedef struct least_ 11 { 12 int next; 13 Position to; 14 int cost; 15 }Edge_Set; 16 17 static Edge_Set edge[2000010];//存边 18 static Position Head[1005]; 19 static int dist[1005]; 20 static int out[1005];//记录出去多少次 21 static bool used[1005];//记录是否在队内 22 23 void SPFA(const int, const int); 24 25 int main(void) 26 { 27 int cows_sum, ML, MD, i, cost, edge_sum; 28 Position from, to; 29 while (~scanf("%d%d%d", &cows_sum, &ML, &MD)) 30 { 31 memset(Head, -1, sizeof(Head)); memset(dist, 0x7f, sizeof(dist)); memset(used, 0, sizeof(used)); memset(out, 0, sizeof(out)); 32 edge_sum = 0; 33 //读入邻接表 34 for (i = 0; i < ML; i++)//d[BL]-d[AL]<=DL->->->d[AL]+DL>=d[BL] 35 { 36 scanf("%d%d%d", &from, &to, &cost);//因为编号是有序的,所以只用储存单向边就可以了 37 edge[edge_sum].next = Head[from]; edge[edge_sum].to = to; edge[edge_sum].cost = cost; 38 Head[from] = edge_sum++; 39 } 40 for (i = 0; i < MD; i++)//d[BL]-d[AL]>=DL->->->d[BD]-DD>=d[AD] 41 { 42 scanf("%d%d%d", &from, &to, &cost); 43 edge[edge_sum].next = Head[to]; edge[edge_sum].to = from; edge[edge_sum].cost = -cost; 44 Head[to] = edge_sum++; 45 } 46 for (i = 1; i + 1 <= cows_sum; i++)//d[i+1]+0>=d[i] 47 { 48 edge[edge_sum].next = Head[i + 1]; edge[edge_sum].to = i; edge[edge_sum].cost = 0; 49 Head[i + 1] = edge_sum++; 50 } 51 SPFA(cows_sum, edge_sum); 52 } 53 return 0; 54 } 55 56 void SPFA(const int cows_sum, const int edge_sum)//这次用STL玩玩 57 { 58 Position out_pos, to; 59 queue<Position>que; 60 que.push(1); dist[1] = 0; used[1] = 1; 61 62 while (!que.empty()) 63 { 64 out_pos = que.front(); que.pop(); 65 used[out_pos] = 0;//出队了就标记为0 66 out[out_pos]++; 67 if (out[out_pos] > cows_sum) 68 { 69 printf("-1 "); 70 return; 71 } 72 for (int k = Head[out_pos]; k != -1; k = edge[k].next) 73 { 74 to = edge[k].to; 75 if (dist[to] > dist[out_pos] + edge[k].cost) 76 { 77 dist[to] = dist[out_pos] + edge[k].cost; 78 if (!used[to]) 79 { 80 used[to] = 1; 81 que.push(to); 82 } 83 } 84 } 85 } 86 if (dist[cows_sum] == MAX) 87 printf("-2 "); 88 else 89 printf("%d ", dist[cows_sum]); 90 }