1. 程式人生 > >【BZOJ1202/HNOI2005】狡猾的商人

【BZOJ1202/HNOI2005】狡猾的商人

解析:

  並查集/差分約束。   差分約束是很明顯的,對於每次記錄之間分別建立(s1,t,v)(t,s,v)(s-1,t,v),(t,s,-v)的有向邊,然後SPFA判負環就行了。   為什麼可以用並查集呢,是因為存在關係的傳遞.   一旦已經知道了s[a]s[b],s[b]s[c]s[a]-s[b],s[b]-s[c]ss為字首和),再給出一條[a,c][a,c]就可以判斷"賬本的真假"了。那麼就可以用並查集維護sumsumsum[i]sum[i]表示以ii為右端點與其最左端點之間的差。如果s

,ts,t在同一個連通塊中,那麼它們之間的和即為s[s]s[t1]=(s[s1]s[rt])(s[t]s[rt])=sum[s1]sum[t]s[s]-s[t-1]=(s[s-1]-s[rt])-(s[t]-s[rt])=sum[s-1]-sum[t]

程式碼(差分約束):

#include <bits/stdc++.h>
using namespace std;

const int Max=105;
int t,n,m,size,tag;
int first[
Max],dis[Max],v[Max],sum[Max]; struct shu{int to,next,len;}e[4005]; inline int get_int() { int x=0,f=1;char c; for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar()); if(c=='-') f=-1,c=getchar(); for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0'; return x*f; } inline
void clean(){size=tag=0;for(int i=0;i<=n+1;i++) dis[i]=1e9,v[i]=first[i]=sum[i]=0;} inline void build(int x,int y,int z){e[++size].next=first[x],first[x]=size,e[size].to=y,e[size].len=z;} inline bool SPFA(int s) { queue<int>q; q.push(s),sum[s]++,dis[s]=0; while(q.size()) { int p=q.front();q.pop();v[p]=0; for(int u=first[p];u;u=e[u].next) { int to=e[u].to; if(dis[to]>dis[p]+e[u].len) { dis[to]=dis[p]+e[u].len; if(!v[to]) { sum[to]++; if(sum[to] >= n) return 0; v[to]=1,q.push(to); } } } } return 1; } inline void init() { t=get_int(); while(t--) { n=get_int(),m=get_int();clean(); for(int i=1;i<=m;i++) { int x=get_int(),y=get_int(),z=get_int(); build(y,x-1,-z),build(x-1,y,z); } for(int i=0;i<=n;i++) build(n+1,i,0); if(!SPFA(n+1)) puts("false"); else puts("true"); } } int main() { init(); return 0; }

程式碼:

#include <bits/stdc++.h>
using namespace std;

const int Max=10005;
int n,m,t,tag;
int fa[Max],d[Max];

inline int get_int()
{
	int x=0,f=1;char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline int get(int v)
{
	if(fa[v]==v) return v;
	int root=get(fa[v]);
	d[v]+=d[fa[v]];
	return fa[v]=root;
}
inline void init()
{
	t=get_int();
	while(t--)
	{
	  n=get_int(),m=get_int(),tag=0;
	  for(int i=0;i<=n;i++) fa[i]=i,d[i]=0;
	  while(m--)
	  {
	  	int x=get_int()-1,y=get_int(),z=get_int();
	  	if(get(x)==get(y))
		{
		  if(d[x]-d[y]!=z) tag=1;
		}
	  	else
	  	{
	  	  int fx=get(x),fy=get(y);
	  	  fa[fy]=fx,d[fy]=d[x]-d[y]-z;
	  	}
	  }
	  tag?puts("false"):puts("true");
	}
}

int main()
{
	init();
	return 0;
}