BZOJ 4500: 矩阵 差分约束
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=4500
题解:
从行向列建边,代表一个格子a[i][j],对每个顶点的所有操作可以合并在一起用sum[xi]表示,
那么题目相当于是要求sum[xi]+sum[xj]==a[xi][xj];
等价于:sum[xj]-(-sum[xi])==a[xi][xj]
等价于:sum[xj]-sum'[xi]<=a[xi][xj] && sum[xj]-sum'[xi]>=a[xi][xj]
等价于:sum[xj]<=sum'[xi]+w && sum'[xi]<=sum[xj]+(-w)
所有就可以用差分约束来做了。跑一遍最短路,判一下负环就可以了。
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<queue> using namespace std; const int maxn = 2222; const int INF = 0x3f3f3f3f; struct Edge { int v, w; Edge(int v, int w) :v(v), w(w) {} Edge() {} }; int n, m,k; vector<Edge> egs; vector<int> G[maxn]; void addEdge(int u, int v, int w) { G[u].push_back(egs.size()); egs.push_back(Edge(v,w)); } bool inq[maxn]; int cnt[maxn]; int d[maxn]; bool spfa() { memset(inq, 0, sizeof(inq)); memset(cnt, 0, sizeof(cnt)); for (int i = 0; i <= n + m; i++) d[i] = INF; queue<int> Q; d[0] = 0; inq[0] = true; Q.push(0); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; for (int i = 0; i < G[u].size(); i++) { Edge& e = egs[G[u][i]]; if (d[e.v] > d[u] + e.w) { d[e.v] = d[u] + e.w; if (!inq[e.v]) { Q.push(e.v); inq[e.v] = true; if (++cnt[e.v] > n+m+1) { return false; } } } } } return true; } void init() { for (int i = 0; i <= n + m; i++) G[i].clear(); egs.clear(); } int main() { int tc; scanf("%d", &tc); while (tc--) { scanf("%d%d%d", &n, &m, &k); init(); for (int i = 0; i < k; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); addEdge(u, v+n, w); addEdge(v+n, u, -w); } for (int i = 1; i <= n + m; i++) { addEdge(0, i, 0); } if (spfa()) { puts("Yes"); } else { puts("No"); } } return 0; } /* 2 2 2 4 1 1 0 1 2 0 2 1 2 2 2 2 2 2 4 1 1 0 1 2 0 2 1 2 2 2 1 */