POJ--1275(差分约束,建图*)

2015-01-09 22:37:22

思路:这道题的建图花了我好久.....

  首先,考虑到起点选定的问题,我们将时刻都往后移动一个小时,变为1,2,3...24这样(于是就有了起点0)

  然后就是根据约束关系建图了,见注释。

  关键在于 i <= 8 的情况:S[i + 16] <= S[i] + S[24] - R[i]

  发现S[24]实际上就是答案,而且目前不知道,所以并不符合正常的差分约束写法,那么我们只要二分一下S[24]的取值,然后判断答案是否可行即可(二分范围:0~N)

(1)用Dfs版Spfa判负环:

  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 = 100;
 22 
 23 //求最小值,用最长路,将时间看做从1开始..24是结尾。
 24 
 25 //定义:num[i]:i时刻开始工作的人数 , req[i]:申请在i时刻开始工作的人总数
 26 //定义:S[i] = num[1]+num[2]+...+num[i]
 27 //<1> S[i] - S[i - 8] >= R[i]   -->  S[i - 8] <= S[i] - R[i] 
 28 //   --> i > 8  : S[i - 8] <= S[i] - R[i]
 29 //   --> i <= 8 : S[i] + S[24] - S[i + 16] >= R[i] --> S[i + 16] <= S[i] + S[24] - R[i]
 30 
 31 //<2> S[i] - S[i - 1] <= req[i] --> S[i] <= S[i - 1] + req[i]
 32 //<3> S[i] - S[i - 1] >= 0      --> S[i - 1] <= S[i] + 0
 33 
 34 int T,R[maxn],N,req[maxn];
 35 int first[maxn],f1[maxn],ecnt,ans;
 36 int ins[maxn],dis[maxn],vis[maxn];
 37 
 38 struct edge{
 39     int v,next,cost;
 40 }e[maxn << 1];
 41 
 42 void Add_edge(int u,int v,int c){
 43     e[++ecnt].next = first[u];
 44     e[ecnt].v = v;
 45     e[ecnt].cost = c;
 46     first[u] = ecnt;
 47 }
 48 
 49 bool Dfs(int p){
 50     ins[p] = vis[p] = 1;
 51     for(int i = first[p]; ~i; i = e[i].next){
 52         int v = e[i].v;
 53         if(dis[v] > dis[p] + e[i].cost){
 54             dis[v] = dis[p] + e[i].cost;
 55             if(ins[v] || !Dfs(v))
 56                 return false;
 57         }
 58     }
 59     ins[p] = 0;
 60     return true;
 61 }
 62 
 63 bool Spfa(){
 64     memset(ins,0,sizeof(ins));
 65     memset(vis,0,sizeof(vis));
 66     memset(dis,0,sizeof(dis));
 67     for(int i = 0; i <= 24; ++i) if(!vis[i]){
 68         if(!Dfs(i)) return false;
 69     }
 70     return true;
 71 }
 72 
 73 int Solve(){
 74     int l = 0,r = N;
 75     int precnt = ecnt,flag = 0;
 76     memcpy(f1,first,sizeof(first));
 77     while(l < r){
 78         int mid = getmid(l,r);
 79         //Build_graph
 80         memcpy(first,f1,sizeof(f1));
 81         ecnt = precnt;
 82         for(int i = 1; i <= 8; ++i){
 83             Add_edge(i,i + 16,mid - R[i]);
 84         }
 85         if(Spfa()) flag = 1,ans = mid,r = mid;
 86         else l = mid + 1;
 87     }
 88     return flag;
 89 }
 90 
 91 int main(){
 92     int t;
 93     scanf("%d",&T);
 94     while(T--){
 95         memset(first,-1,sizeof(first));
 96         ecnt = 0;
 97         for(int i = 1; i <= 24; ++i){
 98             scanf("%d",&R[i]);
 99             if(i > 8) Add_edge(i,i - 8,-R[i]);
100         }
101         scanf("%d",&N);
102         memset(req,0,sizeof(req));
103         for(int i = 1; i <= N; ++i){
104             scanf("%d",&t);
105             req[t + 1]++;
106         }
107         for(int i = 1; i <= 24; ++i){
108             Add_edge(i - 1,i,req[i]);
109             Add_edge(i,i - 1,0);
110         }
111         if(!Solve()) printf("No Solution\n");
112         else printf("%d\n",ans);
113     }
114     return 0;
115 }

(2)用Bellman-Ford判负环:

  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 = 100;
 22 
 23 //求最小值,用最长路,将时间看做从1开始..24是结尾。
 24 
 25 //定义:num[i]:i时刻开始工作的人数 , req[i]:申请在i时刻开始工作的人总数
 26 //定义:S[i] = num[1]+num[2]+...+num[i]
 27 //<1> S[i] - S[i - 8] >= R[i]   --> S[i] >= S[i - 8] + R[i]
 28 //   --> i > 8 : S[i] >= S[i - 8] + R[i]
 29 //   --> i <= 8  : S[i] + S[24] - S[i + 16] >= R[i] --> S[i] >= S[i + 16] + R[i] - S[24]
 30 
 31 //<2> S[i] - S[i - 1] <= req[i] --> S[i - 1] >= S[i] - req[i]
 32 //<3> S[i] - S[i - 1] >= 0      --> S[i] >= S[i - 1] + 0
 33 
 34 int T,R[maxn],N,req[maxn];
 35 int first[maxn],f1[maxn],ecnt,ans;
 36 int dis[maxn];
 37 
 38 struct edge{
 39     int u,v,next,cost;
 40 }e[maxn << 1];
 41 
 42 void Add_edge(int u,int v,int c){
 43     e[++ecnt].next = first[u];
 44     e[ecnt].u = u;
 45     e[ecnt].v = v;
 46     e[ecnt].cost = c;
 47     first[u] = ecnt;
 48 }
 49 
 50 bool BF(){
 51     fill(dis,dis + 24 + 1,INF);
 52     dis[0] = 0;
 53     for(int k = 1; k <= 25; ++k){
 54         for(int i = 1; i <= ecnt; ++i){
 55             int u = e[i].u;
 56             int v = e[i].v;
 57             int c = e[i].cost;
 58             if(dis[v] > dis[u] + c)
 59                 dis[v] = dis[u] + c;
 60         }
 61     }
 62     for(int i = 1; i <= ecnt; ++i){
 63         int u = e[i].u;
 64         int v = e[i].v;
 65         int c = e[i].cost;
 66         if(dis[v] > dis[u] + c){
 67             return false;
 68         }
 69     }
 70     return true;
 71 }
 72 
 73 int Solve(){
 74     int l = 0,r = N;
 75     int precnt = ecnt,flag = 0;
 76     while(l < r){
 77         int mid = getmid(l,r);
 78         //Build_graph
 79         ecnt = precnt;
 80         for(int i = 1; i <= 8; ++i){
 81             Add_edge(i,i + 16,mid - R[i]);
 82         }
 83         if(BF()) flag = 1,ans = mid,r = mid;
 84         else l = mid + 1;
 85     }
 86     return flag;
 87 }
 88 
 89 int main(){
 90     int t;
 91     scanf("%d",&T);
 92     while(T--){
 93         memset(first,-1,sizeof(first));
 94         ecnt = 0;
 95         for(int i = 1; i <= 24; ++i){
 96             scanf("%d",&R[i]);
 97             if(i > 8) Add_edge(i,i - 8,-R[i]);
 98         }
 99         scanf("%d",&N);
100         memset(req,0,sizeof(req));
101         for(int i = 1; i <= N; ++i){
102             scanf("%d",&t);
103             req[t + 1]++;
104         }
105         for(int i = 1; i <= 24; ++i){
106             Add_edge(i - 1,i,req[i]);
107             Add_edge(i,i - 1,0);
108         }
109         if(!Solve()) printf("No Solution\n");
110         else printf("%d\n",ans);
111     }
112     return 0;
113 }
View Code

 

posted @ 2015-01-09 23:05  Naturain  阅读(128)  评论(0编辑  收藏  举报