HDU--1534(差分约束)

2015-01-08 01:06:22

思路:

  这题有两种思路。

(1)第一种也是我一开始想的:拆点,将一个任务拆成开始的时间点和结束的时间点,让任务1拥有1,2点,任务2拥有3,4点,...以此类推第i个任务开始点:2*i-1,结束点:2*i

  那么约束条件就变为:S(2*i) - S(2*i-1) >= t[i]

              S(2*i) - S(2*i-1) <= t[i]   (这样就保证了任务时长为t[i])

        FAS:    S(2*a) - S(2*b-1) >= 0

        FAF:    S(2*a) - S(2*b)    >= 0

        SAF:    S(2*a-1) - S(2*b) >= 0

        SAS:    S(2*a-1) - S(2*b-1) >= 0

  由于要求的是最小需要时间,所以建完这些边后加入一个超级源点,与所有点建边,权为0,跑一遍最长路即可。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <iostream>
11 #include <algorithm>
12 using namespace std;
13 #define lp (p << 1)
14 #define rp (p << 1|1)
15 #define getmid(l,r) (l + (r - l) / 2)
16 #define MP(a,b) make_pair(a,b)
17 typedef long long ll;
18 typedef unsigned long long ull;
19 typedef pair<int,int> pii;
20 const int INF = (1 << 30) - 1;
21 const int maxn = 20010;
22 
23 int n,t[maxn];
24 int first[maxn],ecnt;
25 int inq[maxn],cnt[maxn],dis[maxn];
26 
27 struct edge{
28     int v,next,cost;
29 }e[maxn << 1];
30 
31 void Add_edge(int u,int v,int c){
32     e[++ecnt].next = first[u];
33     e[ecnt].v = v;
34     e[ecnt].cost = c;
35     first[u] = ecnt;
36 }
37 
38 bool Spfa(int s){
39     queue<int> Q;
40     memset(inq,0,sizeof(inq));
41     memset(cnt,0,sizeof(cnt));
42     fill(dis + 1,dis + 2 * n + 1,-INF);
43     dis[s] = 0;
44     cnt[s] = 1;
45     Q.push(s);
46     while(!Q.empty()){
47         int x = Q.front(); Q.pop();
48         inq[x] = 0;
49         for(int i = first[x]; i != -1; i = e[i].next){
50             int v = e[i].v;
51             if(dis[v] < dis[x] + e[i].cost){
52                 dis[v] = dis[x] + e[i].cost;
53                 if(inq[v] == 0){
54                     inq[v] = 1;
55                     if(++cnt[v] > 2 * n + 1) return false;
56                     Q.push(v);
57                 }
58             }
59         }
60     }
61     return true;
62 }
63 
64 int main(){
65     char s[10];
66     int a,b,Case = 0;
67     while(scanf("%d",&n) != EOF,n){
68         memset(first,-1,sizeof(first));
69         ecnt = 0;
70         for(int i = 1; i <= n; ++i){
71             scanf("%d",&t[i]);
72             Add_edge(2 * i - 1,2 * i,t[i]);
73             Add_edge(2 * i,2 * i - 1,-t[i]);
74         }
75         while(scanf("%s",s) != EOF){
76             if(s[0] == '#') break;
77             scanf("%d%d",&a,&b);
78             if(s[0] == 'F'){
79                 if(s[2] == 'S') Add_edge(2 * b - 1,2 * a,0);
80                 else Add_edge(2 * b,2 * a,0);
81             }
82             else{
83                 if(s[2] == 'F') Add_edge(2 * b,2 * a - 1,0);
84                 else Add_edge(2 * b - 1,2 * a - 1,0);
85             }
86         }
87         for(int i = 2 * n; i >= 1; --i) Add_edge(0,i,0);
88         printf("Case %d:\n",++Case);
89         if(Spfa(0) == false) printf("impossible\n");
90         else{
91             for(int i = 1; i <= n; ++i)
92                 printf("%d %d\n",i,dis[2 * i - 1]);
93         }
94         puts("");
95     }
96     return 0;
97 }
View Code

(2)第二种就比较正常一点了。 每个任务一个点,表示任务开始时间。当然超级源点也是要建的(不然就要把所有点先全部入队...也是一种写法)

        FAS:    S(a) + t[a] - S(b)   >= 0

        FAF:    S(a) + t[a] - (S(b) + t[b]) >= 0

        SAF:    S(a) - (S(b) + t[b]) >= 0

        SAS:    S(a) - S(b)             >= 0

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <vector>
 6 #include <map>
 7 #include <set>
 8 #include <stack>
 9 #include <queue>
10 #include <iostream>
11 #include <algorithm>
12 using namespace std;
13 #define lp (p << 1)
14 #define rp (p << 1|1)
15 #define getmid(l,r) (l + (r - l) / 2)
16 #define MP(a,b) make_pair(a,b)
17 typedef long long ll;
18 typedef unsigned long long ull;
19 typedef pair<int,int> pii;
20 const int INF = (1 << 30) - 1;
21 const int maxn = 20010;
22 
23 int n,t[maxn];
24 int first[maxn],ecnt;
25 int inq[maxn],cnt[maxn],dis[maxn];
26 
27 struct edge{
28     int v,next,cost;
29 }e[maxn << 1];
30 
31 void Add_edge(int u,int v,int c){
32     e[++ecnt].next = first[u];
33     e[ecnt].v = v;
34     e[ecnt].cost = c;
35     first[u] = ecnt;
36 }
37 
38 bool Spfa(int s){
39     queue<int> Q;
40     memset(inq,0,sizeof(inq));
41     memset(cnt,0,sizeof(cnt));
42     fill(dis + 1,dis + n + 1,-INF);
43     dis[s] = 0;
44     cnt[s] = 1;
45     Q.push(s);
46     while(!Q.empty()){
47         int x = Q.front(); Q.pop();
48         inq[x] = 0;
49         for(int i = first[x]; i != -1; i = e[i].next){
50             int v = e[i].v;
51             if(dis[v] < dis[x] + e[i].cost){
52                 dis[v] = dis[x] + e[i].cost;
53                 if(inq[v] == 0){
54                     inq[v] = 1;
55                     if(++cnt[v] > n + 1) return false;
56                     Q.push(v);
57                 }
58             }
59         }
60     }
61     return true;
62 }
63 
64 int main(){
65     char s[10];
66     int a,b,Case = 0;
67     while(scanf("%d",&n) != EOF,n){
68         memset(first,-1,sizeof(first));
69         ecnt = 0;
70         for(int i = 1; i <= n; ++i) scanf("%d",t + i);
71         while(scanf("%s",s) != EOF && s[0] != '#'){
72             scanf("%d%d",&a,&b);
73             if(s[0] == 'F'){
74                 if(s[2] == 'S') Add_edge(b,a,-t[a]);
75                 else Add_edge(b,a,t[b] - t[a]);
76             }
77             else{
78                 if(s[2] == 'F') Add_edge(b,a,t[b]);
79                 else Add_edge(b,a,0);
80             }
81         }
82         for(int i = 1; i <= n; ++i) Add_edge(0,i,0);
83         printf("Case %d:\n",++Case);
84         if(Spfa(0) == false) printf("impossible\n");
85         else{
86             for(int i = 1; i <= n; ++i)
87                 printf("%d %d\n",i,dis[i]);
88         }
89         puts("");
90     }
91     return 0;
92 }
View Code

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4209813.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值