poj 3436 ACM Computer Factory顶点流量限制+路径输出

it2022-05-05  125

http://poj.org/problem?id=3436

题意可以看vjudge里面的

 

假如a的输出结构等于b的输入结构,那么就可以连一条边。

边的容量是INF,但是点是有上限的,所以我们将点拆开,一个点变成两个点,中间有一条容量为点容量的线连接。

当然需要加上对于输入结构是0 0 0 0 ...的要连接超级源点和输出结构是 1 1 1 1 1.....的要链接超级汇点,容量依然是INF

本题使用dinic算法,我们可以使用一个m数组,记录dinic的价值变化,具体可以看代码,在有关地方都有标注

#include<cstdio> #include<cstring> #include<vector> #include<queue> #include<algorithm> #include<iostream> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e5; struct node { int to, val, nxt; }edges[maxn]; int head[maxn], deep[maxn]; int n, p; struct Dinic { int id, s, t; int m[200][200]; //记录 跟着一起加减 void init(int n1,int n2) { id = -1; s = n1; t = n2; //s: 源点 t:汇点 memset(head, -1, sizeof(head)); memset(m, 0, sizeof(m)); } void add_edge(int fro, int to, int val) { edges[++id].to = to; edges[id].val = val; edges[id].nxt = head[fro]; head[fro] = id; edges[++id].to = fro; edges[id].val = 0; edges[id].nxt = head[to]; head[to] = id; } bool bfs() { //建deep memset(deep, 0, sizeof(deep)); deep[s] = 1; queue<int> Q; Q.push(s); while (!Q.empty()) { int now = Q.front(); Q.pop(); for (int i = head[now]; i != -1; i = edges[i].nxt) { int to = edges[i].to; if (edges[i].val && deep[to] == 0) { deep[to] = deep[now] + 1; if (to == t) return 1; Q.push(to); } } } return 0; } int dfs(int point , int flow) { if (point == t) return flow; int lat_cost, cost = 0; for (int i = head[point]; i != -1; i = edges[i].nxt) { int to = edges[i].to; if (deep[to] == deep[point] + 1 && edges[i].val) { lat_cost = dfs(to, min(flow - cost, edges[i].val)); // ? if (lat_cost > 0) { m[point][to] += lat_cost; m[to][point] -= lat_cost; //记录路径 edges[i].val -= lat_cost; edges[i ^ 1].val += lat_cost; cost += lat_cost; if (flow == cost) break; } } } return cost; } void Output() { //输出路径 int cnt = 0; vector<int> r; for (int i = 2; i <= 2*p+ 1 ; i+=2) { for (int j = 1; j <= 2 * p + 1 ; j+=2) { if (j == i - 1) continue; if (m[i][j]) { cnt++; //cout << i / 2 << " " << (j + 1) / 2 <<" "<< m[i][j] << endl; r.push_back(i / 2); r.push_back((j + 1) / 2); r.push_back(m[i][j]); } } } cout << cnt << endl; for (int i = 0; i < cnt; i++) { cout << r[3 * i] << " " << r[3 * i + 1] <<" "<< r[3 * i + 2] << endl; } } int dinic() { int ans = 0; while (bfs()) { ans += dfs(s, INF); } return ans; } }; Dinic dic; int sfro[55][15], sto[55][15], val[55]; bool Check_beg(int i) { //检查是否与超级源点链接 for (int j = 1; j <= n; j++) { if (sfro[i][j]==1) { //等于0和2都可以,等于1就退出 return 0; } } return 1; } bool Check_end(int i) { //检查是否与超级汇点链接 for (int j = 1; j <= n; j++) { if (sto[i][j] == 0) return 0; } return 1; } int main() { while (scanf("%d %d", &n, &p)!=EOF) { dic.init(0, 2*p + 2); //因为点要裂开,所以点的数量要乘2 for (int i = 1; i <= p; i++) { scanf("%d", val + i); for (int j = 1; j <= n; j++) { scanf("%d", &sfro[i][j]); } for (int j = 1; j <= n; j++) { scanf("%d", &sto[i][j]); } } //总体应该*2 入: 2*i-1 出 2*i 汇点2*p+2 for (int i = 1; i <= p; i++) { dic.add_edge(2 * i - 1, 2 * i, val[i]); if (Check_beg(i)) { dic.add_edge(0, 2*i-1, INF); } if (Check_end(i)) { dic.add_edge(2*i, 2*p + 2, INF); } for (int j = 1; j <= p; j++) { if (i == j) continue; int ok = 1; for (int k = 1; k <= n; k++) { if (!(sto[i][k] == sfro[j][k] || sfro[j][k] == 2)) { ok = 0; break; } } if (ok == 1) { //建边 dic.add_edge(2*i, 2*j-1, INF); } } } cout << dic.dinic() << " "; dic.Output(); } }

 


最新回复(0)