这应该算是一道比较水的差分约束题了
(不过为啥不开o2炸了啊)我这是最大值写法
操作1:a到b连一条值为-c的有向边
操作2:b到a连一条值为c的有向边
操作3:a到b连一条值为0的双向边
小 K 在 MC 里面建立很多很多的农场,总共 nnn 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 mmm 个),以下列三种形式描述:
但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
第一行包括两个整数 nnn 和 mmm,分别表示农场数目和小 K 记忆中的信息数目。
接下来 mmm 行:
如果存在某种情况与小 K 的记忆吻合,输出 Yes
,否则输出 No
。
输入 #1
3 3 3 1 2 1 1 3 1 2 2 3 2
输出 #1
Yes
数据规模与约定
对于 100%100\%100% 的数据,保证 1≤n,m,a,b,c≤100001 \le n,m,a,b,c \le 100001≤n,m,a,b,c≤10000
#include
#include
#include
#define MAX 300000
#define INF 0x3f3f3f
using namespace std;
struct Edge{
int from,to,vel,next;
};
Edge edge[MAX];
int head[MAX];
int dist[MAX],vis[MAX];
int used[MAX];
int n,m,w,cnt;
void addedge(int u,int v,int w)
{
Edge E={u,v,w,head[u]};
edge[cnt]=E;
head[u]=cnt++;
}
int SPFA(int t)
{
queueQ;
memset(dist,INF,sizeof(dist));
memset(vis,0,sizeof(vis));
memset(used,0,sizeof(used));
used[t]++; // 记录元素 入队次数
vis[t]=1; // 起点从 1 开始
dist[t]=0;
Q.push(t);
while(!Q.empty())
{
int u=Q.front();
Q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(dist[v]>dist[u]+edge[i].vel)
{
dist[v]=dist[u]+edge[i].vel;
if(vis[v]==0)
{
used[v]++; // 每次进队 次数加 1
if(used[v]>n) // 任意元素入队次数大于 N 说明有负环
return 1;
vis[v]=1;
Q.push(v);
}
}
}
}
return 0;
}
int main()
{
int F,a,b,t;
//scanf("%d",&F);
F=1;
while(F--)
{
memset(head,-1,sizeof(head));
cnt=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) addedge(0,i,0);
for(int i=1;i<=m;++i)
{
int op;
scanf("%d",&op);
//scanf("%d%d%d",&a,&b,&t);//s-e<=t
if(op==1)
{
scanf("%d%d%d",&a,&b,&t);
addedge(a,b,-t);
}
else if(op==2)
{
scanf("%d%d%d",&a,&b,&t);
addedge(b,a,t);
}
else
{
scanf("%d%d",&a,&b);
addedge(a,b,0);addedge(b,a,0);
}
//addedge(e,s,t);
}
if(SPFA(0)==0)
{
printf("Yes\n");
}
else
printf("No\n");
}
return 0;
}