小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:
但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
输入格式:
第一行包括两个整数 n 和 m,分别表示农场数目和小 K 记忆中的信息数目。
接下来 m 行:
如果每行的第一个数是 1,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至少多种植了 c 个单位的作物。
如果每行的第一个数是 2,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至多多种植了 c 个单位的作物。如果每行的第一个数是 3,接下来有 2 个整数 a,b,表示农场 a 种植的的数量和 b 一样多。
输出格式:
如果存在某种情况与小 K 的记忆吻合,输出“Yes”,否则输出“No”。
在图上用x->y的边权c表示v(x)-v(y)>=c(或小于等于), 对于多个不等式组:
v(x1) - v(x2) >= c1
v(x2) - v(x3) >= c2
……
把它们加起来就会得到:v(x1) - v(xn) >= c1 + c2 + …… + cn-1;实际上这些不等式组可以看成一个路径,每个不等式即路径上的一小段,毕竟路径总长可以看作每段路径之和。
所以说,按照这种方式建图,就可以包含任意约束条件相加的结果。
输入的三个不等式:a,b,c -> a-b>=c,连a->b权值为c的边 ,a,b,c -> a-b<=c,即b-a>=-c,连b->a权值为-c的边 ,a,b -> a-b>=0,且b-a>=0,即在a,b间接双向边,边权都为0。再设置一个超级源点0,因为图可能不连通,所以要开大点的数组。
#include
#define INF 2333333
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<>n>>m;
while(m--){
cin>>a>>b>>c;
if(a==1)
cin>>d;add(c,b,d);
else if(a==2)
cin>>d;add(b,c,-d);
else if(a==3)
add(b,c,0),add(c,b,0);
}
for(int i=1;i<=n;i++)
add(0,i,0),dis[i]=-INF;
if(!dfs(0))cout<<"No";
else cout<<"Yes";
return 0;
}
还有一种类似于BFS的spfa,不过会TLE:
#include
#define INF 0x3f3f3f3f
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define IOS ios::sync_with_stdio(false)
#define DEBuG cout<q;
q.push(u);
vis[u]=1;
cc[u]=1;
while(!q.empty()){
int s=q.front();q.pop();
vis[s]=0;
if(++cc[s]>n)return 0;//若存在负环,返回false
for(int i=h[s];i;i=no[i].net){
if(dis[no[i].to]>dis[s]+no[i].w){
int j=no[i].to;
dis[j]=dis[s]+no[i].w;
if(!vis[j]){
vis[j]=1;
q.push(j);
}
}
}
}
return 1;
}
int main(){IOS;
cin>>n>>ml;
for(int i=0;i>p>>a>>b;
if(p==3)
{
add(a,b,0);
add(b,a,0);
continue ;
}
cin>>c;
if(p==2)
add(a,b,c);
else
add(b,a,-c);
}
for(int i=1;i<=n;i++){
dis[i]=INF;
add(0,i,0);
}
if(spfa(0))cout<<"Yes";
else cout<<"No";
return 0;
}
双端队列优化:
#include
#define INF 0x3f3f3f3f
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define IOS ios::sync_with_stdio(false)
#define DEBuG cout<q;
q.push_front(u);
vis[u]=1;
cc[u]=1;
while(!q.empty()){
int s=q.front();q.pop_front();
vis[s]=0;
for(int i=h[s];i;i=no[i].net){
if(dis[no[i].to]>dis[s]+no[i].w){
int j=no[i].to;
dis[j]=dis[s]+no[i].w;
cc[j]=cc[s]+1;//这个要注意
if(cc[j]>n)return 0;//若存在负环,返回false
if(!vis[j]){
if(!q.empty() && dis[j]>dis[q.front()])//双端队列优化SPFA如果这个点的dis值大于第一个点的dis值,就普通的将这个点假如队列尾,如果不大于,就将它作为队列的第一个点。这样优化大约能快三分之一
q.push_back(j);
else
q.push_front(j);
vis[j]=1;
}
}
}
}
return 1;
}
int main(){IOS;
cin>>n>>ml;
for(int i=0;i>p>>a>>b;
if(p==3)
{
add(a,b,0);
add(b,a,0);
continue ;
}
cin>>c;
if(p==2)
add(a,b,c);
else
add(b,a,-c);
}
for(int i=1;i<=n;i++){
add(0,i,0);
dis[i]=INF;
}
if(spfa(0))cout<<"Yes";
else cout<<"No";
return 0;
}