// 题意:详细题意省略,要点是求所有人有多少种不同的取值 // 思路:差分约束最短路只能够求满足答案的最大解和最小解,但是对于取值却无法求解 // 可以发现,在一个强量通分量内,从任意点可以到达其他点,也就是说对于两个点,他们一定有一个 A+W1>=B 与 B+W2>=A 的双向限制, 即 W2 >=A-B>= -W1 // 又因为我们的边权只有1,-1,0 所以说我们找到 A-B 的最大差值即是一个scc的贡献 // 但是对于不同的SCC之间只有一个单项边,假设有两个scc A和B, 也就是只有一个单项限制 A-B<=W1 即 B-A>=W1 // 所以对于两个不同SCC我们可以取值使他们之间的贡献没有交集 // 所以最后的答案是所有scc的贡献之和 // // 另外这题要求A-B最大差值,也就是说我要求多源最短路,当然我用单源最短路求出来后 dis[a]-dis[b]也行 // 但是我们也可以直接用floyd,因为这题是个稀疏图(注意数据,这题n只有700,m达到了) // 同时floyd判负环的方式可以看一下!!!!!!!!! // #include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int n, m1, m2; struct edge { int nxt, to, wt; }tr[2 * N]; int head[N], cnt, dis[700][700], vis[700]; void add(int a, int b, int w) { tr[++cnt].to = b; tr[cnt].wt = w; tr[cnt].nxt = head[a]; head[a] = cnt; } int main() { memset(dis, 0x3f, sizeof(dis)); cin >> n >> m1 >> m2; for (int i = 1; i <= n; i++) dis[i][i] = 0; int a, b; for (int i = 1; i <= m1; i++) { cin >> a >> b; dis[a][b] = min(dis[a][b], 1); dis[b][a] = min(dis[b][a], -1); } for (int i = 1; i <= m2; i++) { cin >> a >> b; dis[b][a] = min(dis[b][a],0); } for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) dis[i][j] = min(dis[i][k] + dis[k][j], dis[i][j]); for (int i = 1; i <= n; i++) { if (dis[i][i] < 0) { cout << "NIE" << endl; return 0; }//判负环 } int ans = 0; for(int i=1; i<=n; i++) if (!vis[i]) { vector<int> v; for(int j=1; j<=n; j++) if (dis[j][i] <= n && dis[i][j] <= n) { v.push_back(j); vis[j] = true; } int d = 0; for (auto p : v) for (auto q : v) d = max(d, dis[p][q]); ans += d + 1; v.clear(); }//dls的不用tarjan写法 cout << ans << endl; return 0; } #include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int n, m1, m2; struct edge { int nxt, to, wt; }tr[2 * N]; int head[N], cnt, dis[700][700], ans[700]; void add(int a, int b, int w) { tr[++cnt].to = b; tr[cnt].wt = w; tr[cnt].nxt = head[a]; head[a] = cnt; } int dfn[N], low[N], idx, ins[N], ct, bel[N]; stack<int> stk; vector<int> scc[700]; void dfs(int u) { dfn[u] = low[u] = ++idx; ins[u] = true; stk.push(u); for (int y = head[u]; y; y = tr[y].nxt) { int v = tr[y].to; if (!dfn[v]) dfs(v); if (ins[v]) low[u] = min(low[u], low[v]); } if (dfn[u] == low[u]) { ++ct; while (true) { int v = stk.top(); scc[ct].push_back(v); ins[v] = false; bel[v] = ct; stk.pop(); if (u == v) break; } } } int main() { memset(dis, 0x3f, sizeof(dis)); memset(ans, -1, sizeof(ans)); cin >> n >> m1 >> m2; for (int i = 1; i <= n; i++) dis[i][i] = 0; int a, b; for (int i = 1; i <= m1; i++) { cin >> a >> b; add(b, a, -1); add(a, b, 1); dis[a][b] = min(dis[a][b], 1); dis[b][a] = min(dis[b][a], -1); } for (int i = 1; i <= m2; i++) { cin >> a >> b; add(b, a, 0); dis[b][a] = min(dis[b][a], 0); } for (int i = 1; i <= n; i++) if (!dfn[i]) dfs(i); for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) if (bel[i] == bel[k]) for (int j = 1; j <= n; j++) if (bel[i] == bel[j]) dis[i][j] = min(dis[i][k] + dis[k][j], dis[i][j]); for (int i = 1; i <= n; i++) { if (dis[i][i] < 0) { cout << "NIE" << endl; return 0; }//判负环 } for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (bel[i] == bel[j] && dis[i][j] <= n)//非常的关键,假如说在同一个强联通分量内 dis[i][j] 是被正常更新的,但 dis[j][i] 却不行,因为很可能只存在一条从i到j的单路 ans[bel[j]] = max(ans[bel[j]], dis[i][j]); int tot = 0; for (int i = 1; i <= ct; i++) tot += ans[i]; tot += ct; cout << tot << endl; return 0; }
标签:P3530,cnt,POI2012,700,tr,head,Festival,int,dis From: https://www.cnblogs.com/Aacaod/p/17052826.html