思路:
约束差分,若a-b<=c ,则建立b->a的边,权值为c。根据题意建图,插入超级源点,到达所有顶点且权值为0。
注意:
a=b,就相当于a<=b && a>=b 即建立a->b 权值为0的边和b->a 权值为0的边。
代码:
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
const int MAX_N=10500;
struct edge
{
int to,next,cost;
}e[3*MAX_N];
int p[MAX_N],eid;
void init()
{
memset(p,-1,sizeof(p));
eid=0;
}
void insert(int u,int v,int w)
{
e[eid].to=v;
e[eid].cost=w;
e[eid].next=p[u];
p[u]=eid++;
}
int n;
bool inq[MAX_N];
int cnt[MAX_N];
int d[MAX_N]; // 如果到顶点 i 的距离是 0x3f3f3f3f,则说明不存在源点到 i 的最短路
int spfa(int s) {
memset(inq, 0, sizeof(inq));
memset(d, 0x3f, sizeof(d));
memset(cnt,0,sizeof(cnt));
d[s] = 0;
inq[s] = true;
queue<int> q;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
inq[u] = false;
for (int i = p[u]; i != -1; i = e[i].next) {
int v = e[i].to;
if (d[u] + e[i].cost < d[v]) {
d[v] = d[u] + e[i].cost;
if (!inq[v]) {
q.push(v);
cnt[v]++;
if(cnt[v]>n)
return -1;
inq[v] = true;
}
}
}
}
return 1;
}
int main()
{
int m;
while(cin>>n>>m)
{
init();
for(int i=0;i<m;i++)
{
int a,b,c,t;
cin>>t;
if(t==1)
{
cin>>a>>b>>c;
insert(a,b,-c);
}
if(t==2)
{
cin>>a>>b>>c;
insert(b,a,c);
}
if(t==3)
{
cin>>a>>b;
insert(a,b,0);
insert(b,a,0);
}
}
for(int i=1;i<=n;i++)
insert(0,i,0);
if(spfa(0)==1)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}