BZOJ1202 [HNOI2005]狡猾的商人 spfa

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1202


题意概括

  有一个数列,共n个数字。

  告诉你m个区间和,问是否矛盾。

  数据组数<=100,  n<=100,  m<=1000


题解

  网上都说的并查集的,貌似挺快的。

  我这里给出一个特殊的做法,复杂度O(T(m+n)),T为数据组数。

  我们根据题目给出的信息建图,然后spfa判断。

  对于输入的 a,b,c,我们建立(a,b+1,c)(b+1,a,-c)两条边。

  如果一个点,之前已经被某一个点更新过一次,现在又被某一个点更新了,那么就矛盾了。

  所以,每一个点只会被更新一次,每一条边也最多访问一次,所以复杂度是可以的。

  但是不知道为什么跑了244MS……


 

代码

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=100+5,M=2000+5;
struct Gragh{
	int cnt,x[M],y[M],z[M],nxt[M],fst[N];
	void set(){
		cnt=0;
		memset(fst,0,sizeof fst);
	}
	void add(int a,int b,int c){
		x[++cnt]=a,y[cnt]=b,z[cnt]=c;
		nxt[cnt]=fst[a],fst[a]=cnt;
	}
}g;
int T,n,m,dis[N],vis[N],q[N],head,tail,qmod;
bool check(){
	int x,y,z;
	memset(dis,0,sizeof dis);
	memset(vis,0,sizeof vis);
	qmod=n+2;
	for (int mon=1;mon<=n;mon++){
		if (vis[mon])
			continue;
		head=tail=0;
		q[tail=(tail+1)%qmod]=mon;
		vis[mon]=1;
		while (head!=tail){
			x=q[head=(head+1)%qmod];
			for (int i=g.fst[x];i;i=g.nxt[i]){
				y=g.y[i],z=g.z[i];
				if (!vis[y]){
					vis[y]=1;
					dis[y]=dis[x]+z;
					q[tail=(tail+1)%qmod]=y;
					continue;
				}
				if (dis[y]!=dis[x]+z)
					return 0;
			}
		}
	}
	return 1;
}
int main(){
	scanf("%d",&T);
	while (T--){
		scanf("%d%d",&n,&m);
		g.set();
		for (int i=1,a,b,c;i<=m;i++){
			scanf("%d%d%d",&a,&b,&c);
			if (a>b)
				swap(a,b);
			g.add(a,b+1,c);
			g.add(b+1,a,-c);
		}
		puts(check()?"true":"false");
	}
	return 0;
}

  

  

 

posted @ 2017-08-18 22:02  zzd233  阅读(208)  评论(0编辑  收藏  举报