差分约束
题目大意:给你一系列条件(如SAS u v),根据这些条件推断每个工程开始的最小时间。
蛮简单的一道差分,但是需注意的细节较多。
条件很好找,题目已经给你:
SAS u v :start after start ,即u要在v开始后才能开始。s[u]>=s[v]—>s[u]-s[v]>=0。
SAF u v :start after finish,即u要在v结束后才能开始。s[u]>=s[v]+w[v]—>s[u]-s[v]>=w[v]。
FAS u v :finish after start,即u要在v开始后才能结束。s[u]+w[u]>=s[v]—>s[u]-s[v]>=-w[u]。
FAF u v :finish after finish,即u要在v结束后才能结束。s[u]+w[u]>=s[v]+w[v]—>s[u]-s[v]>=w[v]-w[u]。
因为要求最小值,跑个最长路就行啦!
注意几点(以下为本人各种被坑之后得出来的):
1.第一项工程开始的时间为0。
2.图不一定是联通的,可能有多个连通分量。
3.由于n和m的大小不知道,因此数组尽量开大点(但也别太大,小心炸掉)
4.一种情况输完后要再换一行。(样例上有)
5.n=0的时候就输完啦,跳出最外层的while循环然后return 0。
贴个代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 100000
#define MAXM 2000000
using namespace std;
struct edge{
int next;
int to;
int dis;
};
int h[MAXN],dis[MAXN],w[MAXN],t[MAXN];
int n,m,u,v,d,k;
bool f[MAXN],exist[MAXN];
edge a[MAXM];
int que[5000000]={0};
void read(int x,int y,int z){
k++;
a[k].next=h[x];
a[k].to=y;
a[k].dis=z;
h[x]=k;
}
bool spfa(int j){
memset(f,false,sizeof(f));
que[1]=j; dis[j]=0; f[j]=true; exist[j]=true; t[j]++;
int r=0,w=1;
while (r!=w){
r=(r+1)%5000000;
int x=que[r];
f[x]=false;
for (int i=h[x];i;i=a[i].next)
if (dis[a[i].to]<dis[x]+a[i].dis){
dis[a[i].to]=dis[x]+a[i].dis;
if (!f[a[i].to]){
w=(w+1)%5000000;
que[w]=a[i].to;
f[a[i].to]=true;
exist[a[i].to]=true;
t[j]++;
if (t[j]>n+2)
return false;
}
}
}
return true;
}
int main(){
int num=0;
while (~scanf("%d",&n)&&n){
for (int i=1;i<=n;i++)
scanf("%d",&w[i]);
memset(h,0,sizeof(h));
memset(exist,false,sizeof(exist));
memset(t,0,sizeof(t));
k=0;
char s[10];
while (1){
scanf("%s",s);
if (!strcmp(s,"#"))
break;
scanf("%d%d",&u,&v);
if (!strcmp(s,"SAS"))
read(v,u,0);
if (!strcmp(s,"SAF"))
read(v,u,w[v]);
if (!strcmp(s,"FAS"))
read(v,u,-w[u]);
if (!strcmp(s,"FAF"))
read(v,u,w[v]-w[u]);
}
num++;
printf("Case %d:\n",num);
bool flag=false;
memset(dis,0,sizeof(dis));
for (int i=1;i<=n;i++)
if (!exist[i])
if (!spfa(i)){
flag=true;
break;
}
if (!flag)
for (int i=1;i<=n;i++)
printf("%d %d\n",i,dis[i]);
else
printf("impossible\n");
printf("\n");
}
return 0;
}