题意还是比较耿直的,给你n个点,m组不等式关系,求满足条件的最小解显然是用差分约束系统来解。增加原点0,权值为0.题目要求每个小朋友都必须分到糖果,也就是d[i][0] = 1。
但这个题却不能用传统的spfa来解。比如一下三个不等式:a>b b>c a>c;如果用最短路来解,假设d[a] = 1;那么松弛出来的d[c]必然会是1(a>c)。而根据题意(a>b b>c),显然b
将出现无解的情况。要使一个节点的权值满足所有与其相关的不等式,必须用最长路来解这个题!那么三角不等式就变成了d[v] >= d[u] + dist[u][v]。然后就是按题意建图,从原点跑spfa,最后ans = sum[d]。
#include<iostream> #include<algorithm> #include<vector> #include<string> #include<stack> #include<queue> #include<map> #include<set> #include<cstdio> #include<cstring> #include<cmath> #define FF(i, a, b) for(int i=a; i<b; i++) #define FD(i, a, b) for(int i=a; i>b; i--) #define REP(i, n) for(int i=0; i<n; i++) #define CLR(a, b) memset(a, b, sizeof(a)) #define LL long long using namespace std; const int maxn = 100010; const int INF = 1e9; struct Edge { int from, to, dist; }; int n, m; vector<Edge> edges; vector<int> G[maxn]; bool inq[maxn], flag; int cnt[maxn]; LL d[maxn]; void add(int from, int to, int dist) { edges.push_back((Edge){from, to, dist}); int m = edges.size(); G[from].push_back(m-1); } void init() { flag = 0; REP(i, n+1) G[i].clear(); edges.clear(); FF(i, 1, n+1) add(0, i, 1); } bool spfa() { queue<int> q; q.push(0); CLR(inq, 0); CLR(cnt, 0); REP(i, n+1) d[i] = -1; d[0] = 0, inq[0] = 1, cnt[0] = 1; while(!q.empty()) { int u = q.front(); q.pop(); inq[u] = false; int nc = G[u].size(); REP(i, nc) { Edge& e = edges[G[u][i]]; if(d[e.to] < d[u] + e.dist) { d[e.to] = d[u] + e.dist; if(!inq[e.to]) { q.push(e.to), inq[e.to] = true; if(++cnt[e.to] > n) return true; } } } } return false; } void solve() { if(flag || spfa()) { puts("-1"); return ;} LL ret = 0; FF(i, 1, n+1) ret += d[i]; printf("%lld\n", ret); return ; } int main() { while(~scanf("%d%d", &n, &m)) { init(); int x, a, b; while(m--) { scanf("%d%d%d", &x, &a, &b); if(x == 1) add(a, b, 0), add(b, a, 0); else if(x == 2) { add(a, b, 1); if(a == b) flag = 1; } else if(x == 3) { add(b, a, 0); } else if(x == 4) { add(b, a, 1); if(a == b) flag = 1; } else add(a, b,0); } solve(); } return 0; }