Asia 1996, Shanghai (Mainland China)
题目大意:安排N个工作 ,给你N个工作的开始时间,共有4种安排方式(约束条件)。
条件1:FAF a b,a要在b完成后完成。
条件2:FAS a b,a在在b开始前完成。
条件3:SAS a b,a要在b开始前开始。
条件4:SAF a b,a要在b结束前开始。
给你一系列的约束条件。问:使其工作时间最小且满足所有约束条件的各个工作最早
时间各是什么。如果不满足条件则输出"impossible"。
思路:差分约束系统。设第i件工作的开始时间为t[i]。4个约束条件变成:
条件1:FAF Sa + t[a] - (Sb + t[b]) >= 0
条件2:FAS Sa + t[a] - Sb >= 0
条件3:SAS Sa - Sb >= 0
条件4:SAF Sa - (Sb + t[b]) >= 0
转换为差分约束系统:
条件1:FAF Sb - Sa <= t[a]-t[b]
条件2:FAS Sb - Sa <= t[a]
条件3:SAS Sb - Sa <= 0
条件4:SAF Sb - Sa <= -t[b]
最后求出的Dist[]数组即为各项工作开始的最早时间。不过题目要求最早开始时间为0。
所以计算出Dist[]数组中最小的项,每项工作开始的最早时间减去最小的项即为答案。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int MAXN = 1010; const int MAXM = MAXN*MAXN; const int INF = 0xffffff0; struct EdgeNode { int to; int w; int next; }Edges[MAXM]; int id,Head[MAXN],Dist[MAXN],vis[MAXN],outque[MAXN],num[MAXN]; void AddEdges(int u,int v,int w) { Edges[id].to = v; Edges[id].w = w; Edges[id].next = Head[u]; Head[u] = id++; } bool SPFA(int s,int N) { memset(vis,0,sizeof(vis)); memset(outque,0,sizeof(outque)); for(int i = 0; i <= N; ++i) Dist[i] = INF; queue<int> Q; Dist[s] = 0; vis[s] = 1; Q.push(s); while( !Q.empty() ) { int u = Q.front(); Q.pop(); vis[u] = 0; outque[u]++; if(outque[u] > N) return false; for(int i = Head[u]; i != -1; i = Edges[i].next) { int temp = Dist[u] + Edges[i].w; if(temp < Dist[Edges[i].to]) { Dist[Edges[i].to] = temp; if( !vis[Edges[i].to]) { vis[Edges[i].to] = 1; Q.push(Edges[i].to); } } } } return true; } int main() { int N,kase = 0,u,v; char ch[4]; while(~scanf("%d",&N) && N) { int Min = INF; for(int i = 1; i <= N; ++i) scanf("%d", &num[i]); memset(Head,-1,sizeof(Head)); id = 0; while(scanf("%s",ch) && ch[0] != '#') { scanf("%d%d", &u, &v); if(strcmp(ch,"SAS") == 0) AddEdges(u,v,0); else if(strcmp(ch,"SAF") == 0) AddEdges(u,v,-num[v]); else if(strcmp(ch,"FAS") == 0) AddEdges(u,v,num[u]); else AddEdges(u,v,num[u]-num[v]); } for(int i = 1; i <= N; ++i) AddEdges(0,i,0); printf("Case %d:\n",++kase); if(SPFA(0,N) == 0) { printf("impossible\n\n"); continue; } for(int i = 1; i <= N; ++i) if(Dist[i] < Min) Min = Dist[i]; for(int i = 1; i <= N; ++i) printf("%d %d\n", i, Dist[i]-Min); printf("\n"); } return 0; }