bzoj1202: [HNOI2005]狡猾的商人(差分约束系统)

原题链接

题目描述:***姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的。账本上记录了n个月以来的收入情况,其中第i个月的收入额为Ai(i=1,2,3...n-1,n), 。当 Ai大于0时表示这个月盈利Ai 元,当Ai小于0时表示这个月亏损Ai元。所谓一段时间内的总收入,就是这段时间内每个月的收入额的总和。***姹的任务是秘密进行的,为了调查商人的账本,她只好跑到商人那里打工。她趁商人不在时去偷看账本,可是她无法将账本偷出来,每次偷看账本时她都只能看某段时间内账本上记录的收入情况,并且她只能记住这段时间内的总收入。现在,***姹总共偷看了m次账本,当然也就记住了m段时间内的总收入,你的任务是根据记住的这些信息来判断账本是不是假的。

输入格式:第一行为一个正整数w,其中w <100,表示有w组数据,即w个账本,需要你判断。每组数据的第一行为两个正数n和m,其中n < 100,m<1000,分别表示对应的账本记录了多少个月的收入情况以及偷看了多少次账本。接下来的m行表示***姹偷看m次账本后记住的m条信息,每条信息占一行,有三个整数s,t和v,表示从第s个月到第t个月(包含第t个月)的总收入为v,这里假设s总是小于等于t。

输出格式:包含w行,每行是true或false,其中第i行为true当且仅当第i组数据,即第i个账本不是假的;第i行为false当且仅当第i组数据,即第i个账本是假的。

输入样例
2
3 3
1 2 10
1 3 -5
3 3 -15
5 3
1 5 100
3 5 50
1 2 51

输出样例
true
false

解析:一道巧妙的差分约束题。
   给出某一段的和,即给出sum[t]-sum[s-1]的值。
   所以可以连一条t->s-1权为v的边,连一条s-1->t权为-v的边。
   最后跑一遍最长路,看看有没有环即可。

代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

const int maxn = 105, maxm = 2005;
int w, n, m, dis[maxn], vis[maxn], tim[maxn];
int nxt[maxm], hed[maxm], to[maxm], cnt, val[maxm];
queue <int> que;

int read(void) {
	char c; while (c = getchar(), (c < '0' || c > '9') && c != '-'); int x = 0, y = 1;
	if (c == '-') y = -1; else x = c - '0';
	while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x * y; 
}

void add(int x, int y, int v) {
	nxt[++ cnt] = hed[x]; hed[x] = cnt; to[cnt] = y; val[cnt] = v;
}

void init(void) {
	memset(hed, 0, sizeof(hed));
	cnt = 0;
}

int spfa(int s) {
	  for (int i = 1; i <= n; ++ i) dis[i] = -2e9, vis[i] = 0, tim[i] = 0;
	vis[s] = 1; que.push(s);
	  while (!que.empty()) {
	  	int u = que.front(); que.pop(); vis[u] = 0;
	  	  for (int i = hed[u]; i ; i = nxt[i]) {
	  	  	  int v = to[i];
	  	  	    if (dis[v] < dis[u] + val[i]) {
	  	  	    	  dis[v] = dis[u] + val[i];
	  	  	    	  if (!vis[v]) {
	  	  	    	  	    tim[v] ++;
	  	  	    	  	    if (tim[v] >= n) return 0;
	  	  	    	  	    que.push(v); vis[v] = 1;
						  }
					}
			}
	  }
	return 1;
}

int main() {
	w = read(); 
	  while (w --) {
	  	n = read(); m = read();
	  	init();
	  	  for (int i = 1; i <= m; ++ i) {
	  	  	  int x = read(), y = read(), v = read();
	  	  	  add(y, x - 1, v); add(x - 1, y, -v);
			}
		int flag = 0;
		  for (int i = 0; i <= n; ++ i) {
		  	if (!spfa(i)) {
		  		flag = 1; break;
			  }
		  }
		  if (flag) puts("false"); else puts("true");
	  }
	return 0;
}
posted @ 2019-01-06 12:04  Gax_c  阅读(103)  评论(0编辑  收藏  举报