考察:差分约束
艹,我太菜了,想了半天不知道源点在哪里,结果是每个点都试一遍...
思路:
看了其他大佬的博客,实际我是没有理解差分约束的,这里不需要求最值解,只需要求可行解,而无需管它们的实际意义, 假设所有解都<=0,那么根据条件求出所有解,而所有解+d是满足解<=d的可行解.所以直接建立超级源点就可以.
当存在某个解<=c 就存在了绝对关系,由此可以求出最值解.
1 #include <iostream> 2 #include <cstring> 3 #include <stack> 4 using namespace std; 5 const int N = 110,M = 2010; 6 int n,m,idx,cnt[N],dist[N],h[N]; 7 bool st[N],vis[N]; 8 struct Road{ 9 int fr,to,ne,w; 10 }road[M]; 11 void add(int a,int b,int c) 12 { 13 road[idx].w = c,road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++; 14 } 15 bool spfa(int s) 16 { 17 stack<int> q; 18 dist[s] = 0; st[s] = 1; 19 q.push(s); 20 while(q.size()) 21 { 22 int u = q.top(); 23 st[u] = 0; 24 vis[u] = 1; 25 q.pop(); 26 for(int i=h[u];~i;i=road[i].ne) 27 { 28 int v = road[i].to; 29 if(dist[v]>dist[u]+road[i].w) 30 { 31 dist[v] = dist[u]+road[i].w; 32 cnt[v] = cnt[u]+1; 33 if(cnt[v]>=n+1) return 0; 34 if(!st[v]) q.push(v),st[v] = 1; 35 } 36 } 37 } 38 return 1; 39 } 40 int main() 41 { 42 int T; 43 scanf("%d",&T); 44 while(T--) 45 { 46 scanf("%d%d",&n,&m); 47 idx = 0; 48 memset(h,-1,sizeof h); memset(cnt,0,sizeof cnt); 49 memset(st,0,sizeof st); memset(dist,0,sizeof dist); 50 memset(vis,0,sizeof vis); 51 while(m--) 52 { 53 int a,b,c; scanf("%d%d%d",&a,&b,&c); 54 add(a-1,b,c); add(b,a-1,-c); 55 } 56 bool ok = 1; 57 for(int i=0;i<=n;i++) 58 if(!vis[i]) 59 { 60 ok = spfa(i); 61 if(!ok) break; 62 } 63 if(ok) puts("true"); 64 else puts("false"); 65 } 66 return 0; 67 }
作为本题最后再说明的是:
当我们以初始化dist[s] = w时,实际求出来的所有解都是满足约束条件的,只要不存在环,dist[s]就不会被更新.但是这样是求出Xs = w的条件下求出的所有解,它们不一定有实际意义.但是判环的时候,我们不需要考虑实际意义,而是解是否能被求出.