关键字:差分约束。
Link&Limit
时间限制:1000ms 空间限制:131072kb
Description
小 K 在 Minecraft 里面建立很多很多的农场,总共 n 个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共 m 个),以下列三种形式描述:
1. 农场 a 比农场 b 至少多种植了 c 个单位的作物。
2. 农场 a 比农场 b 至多多种植了 c 个单位的作物。
3. 农场 a 与农场 b 种植的作物数一样多。
但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
Input Format
第一行包括两个整数 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 一样多。
Output Format
如果存在某种情况与小 K 的记忆吻合,输出“Yes”,否则输出“No”。
Sample Input #1
3 3
3 1 2
1 1 3 1
2 2 3 2
Sample Output #1
Yes
Hint
对于 100% 的数据保证:1 ≤ n,m,a,b,c ≤ 10000。
差分约束的裸题。如果构造出来的图中有正环(要算最长路)就是No,否则就是Yes。找正环可以用spfa来做,如果一个点入队超过n次则图中含有正环。不过本题的数据范围这样做可能超时,加个限制会好很多。
差分约束的介绍可见:http://tsreaper.is-programmer.com/posts/180182.html
找环也可以用递归版的spfa:http://hzwer.com/3600.html
#include <stdio.h> #define QLEN 10005 int n,m; int e[30010][3],p[10010],tot = 0; int q[10010],dis[10010],cnt[10010],head,tail,ttail = 0; short vis[10010]; void adde(int sn,int fn,int val) { e[++tot][0] = fn; e[tot][1] = val; e[tot][2] = p[sn]; p[sn] = tot; } short spfa() { int i,sn,fn,val; for(i=1;i<=n;i++) dis[i] = -999999999; head = 1; tail = ttail = 2; vis[0] = 1; cnt[0]++; while(head!=tail) { if(ttail>1000000) return 0; sn = q[head++]; for(i=p[sn];i;i=e[i][2]) { fn = e[i][0]; val = e[i][1]; if(dis[fn]>=dis[sn]+val) continue; dis[fn] = dis[sn]+val; if(vis[fn]) continue; vis[fn] = 1; q[tail++] = fn; cnt[fn]++; ttail++; if(cnt[fn]>n) return 0; if(tail>QLEN) tail = 1; } vis[sn] = 0; if(head>QLEN) head = 1; } return 1; } int main() { int i,opt,sn,fn,val; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) adde(0,i,0); for(i=1;i<=m;i++) { scanf("%d",&opt); if(opt == 1) { scanf("%d%d%d",&sn,&fn,&val); adde(fn,sn,val); } else if(opt == 2) { scanf("%d%d%d",&sn,&fn,&val); adde(sn,fn,-val); } else { scanf("%d%d",&sn,&fn); adde(sn,fn,0); adde(fn,sn,0); } } if(spfa()) printf("Yes"); else printf("No"); return 0; }