小 K 在 MC 里面建立很多很多的农场,总共 n n n 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 m m m 个),以下列三种形式描述:
但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
第一行包括两个整数 n n n 和 m m m,分别表示农场数目和小 K 记忆中的信息数目。
接下来 m m m 行:
如果存在某种情况与小 K 的记忆吻合,输出 Yes
,否则输出 No
。
3 3
3 1 2
1 1 3 1
2 2 3 2
Yes
对于 100 % 100\% 100% 的数据,保证 1 ≤ n , m , a , b , c ≤ 5 × 1 0 3 1 \le n,m,a,b,c \le 5 \times 10^3 1≤n,m,a,b,c≤5×103。
差分约束模型,把每个都分析一下:
#include
using namespace std;
const int MAXN=1e8+5,M=1e6;
vector<pair<int,int> > edges[M];
int dis[M];
int n,m,s;
int cnt[M];
bool inQueue[MAXN];
int q[MAXN],f=1,t=1;
void add(int u,int v,int w){edges[u].emplace_back(v,w);}
void read(){
cin>>n>>m;
for(int i=1,u,v,w,opt;i<=m;i++)
{
cin>>opt>>u>>v;
if(opt<3) cin>>w;
if(opt==1) add(u,v,-w);
if(opt==2) add(v,u,w);
if(opt==3) {add(u,v,0);add(v,u,0);}
}
}
bool spfa(int s=0)
{
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q[t++]=s;
inQueue[s]=true;
while(f<t)
{
int x=q[f++];
inQueue[x]=false;
for(auto& edge:edges[x])
{
if(dis[edge.first]<=dis[x]+edge.second) continue;
dis[edge.first]=dis[x]+edge.second;
if(!inQueue[edge.first])
{
q[t++]=edge.first;
inQueue[edge.first]=true;
cnt[edge.first]++;
if(cnt[edge.first]>=n+1) return false;
}
}
}
return true;
}
void solve(){
for(int i=1;i<=n;i++) add(0,i,0);
if(!spfa()) cout<<"No"; else cout<<"Yes";
}
int main()
{
read();
solve();
return 0;
}
void solve(){
for(int i=1;i<=n;i++) add(0,i,0);
if(!spfa()) cout<<"No"; else cout<<"Yes";
}
差分约束需要超级源点,需要与每个点构成一条边,权值为0,因为spfa可以有效判断负环,if(cnt[edge.first]>=n+1) return false;
需要注意,此处为n+1,因为有超级源点
STL库中的queue效率低下,常数较高,在不开O2的前提下容易tle,推荐手打队: