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 }