Schedule Problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1715 Accepted Submission(s): 757
Special Judge
Problem Description
A
project can be divided into several parts. Each part should be
completed continuously. This means if a part should take 3 days, we
should use a continuous 3 days do complete it. There are four types of
constrains among these parts which are FAS, FAF, SAF and SAS. A
constrain between parts is FAS if the first one should finish after the
second one started. FAF is finish after finish. SAF is start after
finish, and SAS is start after start. Assume there are enough people
involved in the projects, which means we can do any number of parts
concurrently. You are to write a program to give a schedule of a given
project, which has the shortest time.
Input
The input file consists a sequences of projects.
Each project consists the following lines:
the count number of parts (one line) (0 for end of input)
times should be taken to complete these parts, each time occupies one line
a list of FAS, FAF, SAF or SAS and two part number indicates a constrain of the two parts
a line only contains a ‘#‘ indicates the end of a project
Output
Output
should be a list of lines, each line includes a part number and the
time it should start. Time should be a non-negative integer, and the
start time of first part should be 0. If there is no answer for the
problem, you should give a non-line output containing "impossible".
A blank line should appear following the output for each project.
Sample Input
3
2
3
4
SAF 2 1
FAF 3 2
#
3
1
1
1
SAF 2 1
SAF 3 2
SAF 1 3
#
0
Sample Output
Case 1:
1 0
2 2
3 1
Case 2:
impossible
Source
Asia 1996, Shanghai (Mainland China)
题意:有n个项目,每个项目有一个周期,表示完成其的时间,然后下面有一些限制,SAF a b 表示 a 的开始时间要晚于 b的结束时间,FAF,SAS,FAS类似。问每个项目最早的开始时间,依下标输出.
题解:我们假设 a的周期是 v[a] ,开始时间是 s[a],结束时间是 e[a], b类似.
SAF 就可以表示为 s[a] - e[b]>=0 ---->s[a] - (s[b] +v[b] )>=0 这样的话就可以列出很多个关于起点的方程,然后就设立一个超级源点,和每个起点连条长度为 0 的边,从超级源点进行 spfa,得到 low数组后依次输出即可。有环则输出 impossible,今天听说spfa只要进入 sqrt(n) 次就可以判断有没有环了,这个题还真可以。。如果有题超时的话,不妨可以试试。。不过数据强的话另当别论。
#include <iostream> #include <cstdio> #include <string.h> #include <queue> #include <algorithm> #include <math.h> using namespace std; typedef long long LL; const int INF = 999999999; const int N = 1000; struct Edge{ int v,w,next; }edge[10005]; int head[N]; int n,tot; int val[N]; void init(){ memset(head,-1,sizeof(head)); tot = 0; } void addEdge(int u,int v,int w,int &k){ edge[k].v = v,edge[k].w = w,edge[k].next = head[u],head[u] = k++; } int low[N],time[N]; bool vis[N]; int spfa(int s){ for(int i=0;i<=n;i++){ vis[i] = false; low[i] = -INF; time[i] = 0; } low[s] = 0; time[s]++; queue<int> q; q.push(s); int num = ((int)sqrt(n)+1); ///改成根号 n 可以AC... while(!q.empty()){ int u = q.front(); q.pop(); vis[u] = false; for(int k=head[u];k!=-1;k=edge[k].next){ int v = edge[k].v,w=edge[k].w; if(low[v]<low[u]+w){ low[v] = low[u]+w; if(!vis[v]){ vis[v] = true; q.push(v); if(time[v]++>num) return 0; } } } } return 1; } int main(){ int t = 1; while(scanf("%d",&n)!=EOF,n){ init(); int MAX = -1; for(int i=1;i<=n;i++){ scanf("%d",&val[i]); } char str[10]; int super = 0; while(scanf("%s",str)){ if(strcmp(str,"#")==0) break; int a,b; scanf("%d%d",&a,&b); if(strcmp(str,"SAF")==0){ addEdge(b,a,val[b],tot); }else if(strcmp(str,"FAF")==0){ addEdge(b,a,-(val[a]-val[b]),tot); }else if(strcmp(str,"FAS")==0){ addEdge(b,a,-val[a],tot); }else{ addEdge(b,a,0,tot); } } for(int i=1;i<=n;i++){ addEdge(super,i,0,tot); } printf("Case %d:\n",t++); if(spfa(super)){ for(int i=1;i<=n;i++){ printf("%d %d\n",i,low[i]); } }else{ printf("impossible\n"); } printf("\n"); } return 0; }