对于一个刚接触差分约束系统的OIer来说,这算是一道细节比较多,也比较难的题。首先就是这道题有5种不同的约束条件,对于条件1,3,5直接按照差分条件建边即可,条件2,4要先移项,再建边。之后再求单源最长路,好不容易做出来后你就会发现数据卡SPFA!!!!这里可以加两个小小的优化:1)当a,b严格大于或小于时,他们不能为同一个人,先预判出来可以节省大量时间(不加#5会TLE)。还有要倒序建边,,,(没有任何道理,倒序就能AC,正序会TLE)
参考程序如下:
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
long long n,m,dist[350005],v[350005],w[350005],nxt[350005],head[350005],cnt,x,a,b,ring[350005];
bool vis[350005];
inline int read()
{
int f=1,x=0;
char s=getchar();
while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
return x*f;
}
inline void add(int a,int b,int c)
{
v[++cnt]=b;
w[cnt]=c;
nxt[cnt]=head[a];
head[a]=cnt;
}
inline bool spfa(int node)
{
queue<int>q;
q.push(node);
vis[node]=1;
while(!q.empty())
{
int c=q.front();
q.pop();
vis[c]=0;
ring[c]++;
//cout<<c<<endl;
if(ring[c]==n)return 0;
for(int i=head[c];i;i=nxt[i])
{
int y=v[i];
//cout<<"-------------------CJXGBH---------------------"<<endl;
//cout<<dist[y]<<" "<<dist[c]<<" "<<w[i]<<endl;
if(dist[y]<dist[c]+w[i])
{
dist[y]=dist[c]+w[i];
if(!vis[y])
{
q.push(y);
vis[y]=1;
}
}
}
}
return 1;
}
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();
for(int i=1;i<=m;i++)
{
x=read();a=read();b=read();
if(x==1)
{
add(a,b,0);
add(b,a,0);
}
if(x==2)
{
add(a,b,1);
if(a==b)
{
cout<<"-1";
return 0;
}
}
if(x==3)
{
add(b,a,0);
}
if(x==4)
{
add(b,a,1);
if(a==b)
{
cout<<"-1";
return 0;
}
}
if(x==5)
{
add(a,b,0);
}
}
for(int i=n;i>=1;i--)
{
add(0,i,1);
}
if(!spfa(0))
{
cout<<"-1";
return 0;
}
long long ans=0;
for(int i=1;i<=n;i++)ans+=dist[i];
cout<<ans;
return 0;
}
原文:https://www.cnblogs.com/szmssf/p/11079874.html