ShortestPath:Layout(POJ 3169)(差分约束的应用)

                     

                        布局

  题目大意:有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\n");
56     else if (dist[cows_sum] == MAX)
57         printf("-2\n");
58     else printf("%d\n", 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\n");
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\n");
88     else
89         printf("%d\n", dist[cows_sum]);
90 }

posted @ 2015-11-09 23:36  PhiliAI  阅读(286)  评论(0编辑  收藏  举报