题目描述:
现在要针对多赛区竞赛制定一个预算,该预算是一个行代表不同种类支出、列代表不同赛区支出的矩阵。组委会曾经开会讨论过各类支出的总和,以及各赛区所需支出的总和。另外,组委会还讨论了一些特殊的约束条件:例如,有人提出计算机中心至少需要1000K 里亚尔(伊朗货币),用于购买食物;也有人提出Sharif 赛区用于购买体恤衫的费用不能超过30000K 里亚尔。组委会的任务是制定一个满足所有约束条件且行列和满足要求的预算。
解题报告:
该题解题关键在于建图, 将行置于左边,列置于右边,然后连接所有行和列,每条边表示第x行第y列的物品的价格预算。
根据约束条件来限定这些边的上界与下界,从而将题目转化为 有上下界的可行流求解:
已有边的权为c[i][j]-b[i][j]
另外构造源点和汇点 分别连接 所有行 和 所有列
边权为 sum[x]-sum(b[x][i]) sum[y]-sum(b[i][y])
扫描二维码关注公众号,回复:
150542 查看本文章
如果源流和汇流相等 则说明有可行解
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <queue> #include <vector> using namespace std; const int maxn = 300; const int INF = 0x3f3f3f3f; int low[210][22], high[210][22], res[210][22]; int sumr[210], sumc[22]; bool fg; int n, m; struct Edge { int from, to, cap, flow; Edge() { from = to = cap = flow = 0; } Edge(int in1, int in2, int in3, int in4) { from = in1, to = in2, cap = in3, flow = in4; } }; struct Dinic { int s, t; vector<Edge>edges; vector<int>G[maxn]; int d[maxn]; int cur[maxn]; void init() { edges.clear(); for(int i = 0;i < maxn;i ++) G[i].clear(); memset(d, -1, sizeof(d)); memset(cur, 0, sizeof(cur)); } void addedge(int from, int to, int cap) { edges.push_back(Edge(from, to, cap, 0)); edges.push_back(Edge(to, from, 0, 0)); int m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1); } bool bfs() { memset(d, -1, sizeof(d)); queue<int> que; que.push(s); d[s] = 0; while(!que.empty()) { int u = que.front(); que.pop(); for(int i = 0;i < G[u].size();i ++) { Edge &e = edges[G[u][i]]; if(d[e.to] == -1 && e.cap > e.flow) { d[e.to] = d[u] + 1; que.push(e.to); } } } return d[t] != -1; } int dfs(int u, int a) { if(u == t || a == 0) return a; int flow = 0, f; for(int &i = cur[u];i < G[u].size();i ++) { Edge &e = edges[G[u][i]]; if(d[e.to] == d[u] + 1) { f = dfs(e.to, min(a, e.cap - e.flow) ); if(f <= 0) continue; e.flow += f; edges[G[u][i]^1].flow -= f; flow += f; a -= f; if(!a) break; } } if(!flow) d[u] = -2; return flow; } int maxflow(int s, int t) { this->s = s, this->t = t; int flow = 0; while(bfs()) { memset(cur, 0, sizeof(cur)); flow += dfs(s, INF); } return flow; } }D; void fix(int i, int j, char ch, int k) { if(ch == '=') { if(low[i][j] > k) fg = 1; if(high[i][j] < k) fg = 1; low[i][j] = high[i][j] = k; } else if(ch == '<') { if(low[i][j] >= k) fg = 1; if(high[i][j] >= k) high[i][j] = k - 1; } else if(ch == '>') { if(high[i][j] <= k) fg = 1; if(low[i][j] <= k) low[i][j] = k + 1; } } int main() { //freopen("f:\\in.txt","r",stdin); //freopen("f:\\out.txt","w",stdout); int T; scanf("%d", &T); for(int i = 1;i <= T;i ++) { if(i != 1) puts(""); fg = 0; memset(sumc, 0, sizeof(sumc)); memset(sumr, 0, sizeof(sumr)); scanf("%d %d", &n, &m); for(int i = 1;i <= n;i ++) { for(int j = 1;j <= m;j ++) { low[i][j] = 0; high[i][j] = INF; } } for(int i = 1;i <= n;i ++) scanf("%d", &sumr[i]); for(int i = 1;i <= m;i ++) scanf("%d", &sumc[i]); int q; scanf("%d", &q); while(q --) { int a, b, k; char ch; scanf("%d %d %c %d", &a, &b, &ch, &k); if(!a && !b) { for(int i = 1;i <= n;i ++) for(int j = 1;j <= m;j ++) fix(i, j, ch, k); } else if(!a && b) { for(int i = 1;i <= n;i ++) fix(i, b, ch, k); } else if(a && !b) { for(int i = 1;i <= m;i ++) fix(a, i, ch, k); } else { fix(a, b, ch, k); } } if(fg) { puts("IMPOSSIBLE"); continue; } else { D.init(); int s = 0, t = n + m + 1; for(int i = 1;i <= n;i ++) { for(int j = 1;j <= m;j ++) { D.addedge(i, j + n, high[i][j] - low[i][j]); } } int sum = 0; for(int i = 1;i <= n;i ++) { int f = sumr[i]; for(int j = 1;j <= m;j ++) f -= low[i][j]; if(f > 0) sum += f, D.addedge(s, i, f); if(f < 0) D.addedge(i, t, -f); } for(int j = 1;j <= m;j ++) { int f = -sumc[j]; for(int i = 1;i <= n;i ++) f += low[i][j]; if(f > 0) sum += f, D.addedge(s, j + n, f); if(f < 0) D.addedge(j + n, t, -f); } int ans = D.maxflow(s, t); if(ans != sum) { puts("IMPOSSIBLE"); } else { for(int i = 1;i <= n;i ++) for(int j = 1;j <= m;j ++) res[i][j] = low[i][j]; for(int i = 1;i <= n;i ++) { for(int j = 0;j < D.G[i].size();j ++) { Edge &e = D.edges[D.G[i][j]]; if(e.to == s || e.to == t) continue; res[i][e.to-n] += e.flow; } } for(int i = 1;i <= n;i ++) for(int j = 1;j <= m;j ++) printf("%d%c",res[i][j],j==m?'\n':' '); } } } return 0; }