蒜头君的银行卡
描述
虽然蒜头君并没有多少钱,但是蒜头君办了很多张银行卡,共有 n 张,以至于他自己都忘记了每张银行卡里有多少钱了。他只记得一些含糊的信息,这些信息主要以下列三种形式描述:
银行卡 a 比银行卡 b 至少多 c 元。
银行卡 a 比银行卡 b 至多多 c 元。
银行卡 a 和银行卡 c 里的存款一样多。
但是由于蒜头君的记忆有些差,他想知道是否存在一种情况,使得银行卡的存款情况和他记忆中的所有信息吻合。
输入
第一行输入两个整数 n 和 m,分别表示银行卡数目和蒜头君记忆中的信息的数目。(1≤n,m≤10000)
接下来 m 行:
如果每行第一个数是 1,接下来有三个整数 a,b,c,表示银行卡 a 比银行卡 b 至少多 c元。
如果每行第一个数是 2,接下来有三个整数 a,b,c,表示银行卡 a 比银行卡 b 至多多 c元。
如果每行第一个数是 3,接下来有两个整数 a,b,表示银行卡 a 和 b 里的存款一样多。(1≤n,m,a,b,c≤10000)
输出
如果存在某种情况与蒜头君的记忆吻合,输出Yes,否则输出No。
输入样例 1
3 3
3 1 2
1 1 3 1
2 2 3 2
输出样例 1
Yes
提示
提示:a=b 可以写成 a≤b and b≤a。差分约束建图,然后判断是否有负环。
这道题是十分经典的差分约束。
spaf暴力解题,便AC。
代码:
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=10010;
const int maxm=500010;
int n,m;
int dis[maxn];
bool vis[maxn];
int in[maxn];
struct node{
int v,w,next;
node(){}
node(int _v,int _w,int _next){
v=_v;
w=_w;
next=_next;
}
}e[maxm];
int head[maxn],len;
void init(){
memset(head,-1,sizeof head);
len=0;
}
void add(int u,int v,int w){
e[len]=node(v,w,head[u]);
head[u]=len++;
}
void add2(int u,int v,int w){
add(u,v,w);
add(v,u,w);
}
bool spaf(int u){
memset(vis,false,sizeof vis);
memset(dis,inf,sizeof dis);
dis[u]=0;
memset(in,0,sizeof in);
queue<int> qu;
qu.push(u);
vis[u]=1;
in[u]=1;
while(!qu.empty()){
u=qu.front();
qu.pop();
vis[u]=false;
for (int j=head[u];~j;j=e[j].next){
int v=e[j].v;
int w=e[j].w;
if (dis[v]>dis[u]+w) {
dis[v]=dis[u]+w;
if (!vis[v]){
qu.push(v);
vis[v]=true;
in[v]++;
if(in[v]>n+1){
return false;
}
}
}
}
}
return true;
}
int main(){
init();
int u,v,w;
cin>>n>>m;
int op;
while(m--){
cin>>op;
if(op==1){
cin>>u>>v>>w;
add(u,v,-w);
}else if(op==2){
cin>>u>>v>>w;
add(v,u,w);
}else{
cin>>u>>v;
add(u,v,0);
add(v,u,0);
}
}
for(int i=1;i<=n;i++){
add(0,i,0);
}
if(spaf(0)){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
return 0;
}