http://acm.hdu.edu.cn/showproblem.php?pid=3338
题意:
有黑格子和白格子黑格子有数字第一个A意味着向下的白格子的权值和为A, 第二个B意味者向右的权值为B
思路:
咋一看意味是深搜,但数据太大了,结果发现可以用网络流写(其实是看了别人博客-_-),
1。把每个黑格子编号,向下有值的编1 -> rn,向右有值的编rn + 1 -> rn + cn
1。把源点S 与每个向下有值的黑格子相连,汇点T与每个向右有值的黑格子相连。权值都为黑格子的值
2。因为每一个白格子都被用了两次,一次是上方的黑格子用了,一次是左方的黑格子用了,所以黑格子向下的和与向右的权值和相同。(流入流量==流出流量)。
3。把黑格子与它所对应的白格子相连(类似这样)
把每条边的权值赋值为8
4。为什么权值是8
先举个栗子:
一张这样的图(忘画T了。。。)
跑完最大流后
这时1->2是0流,即没有流量流过,而经过这样一个最大流后从S->T最大流把S的流量流完,可以类比到题目
源点S->每个下方有白格子的黑格子->白格子->右方有格子的白格子-> 汇点T
因为可能有0流的存在,所以把黑格子-> 白格子的权值设为8,跑过Dinic后,用9减去每条边的剩余流量就是满足条件流走的最大流,这时,0流减完就为1,这样就不会出现有的白格子里有0的情况,符合题目条件
AC代码
#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <stdio.h>
#include <deque>
using namespace std;
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 1000005
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1000000007
struct Edge{
int v, w, nxt;
}edge[maxn];
struct TU{
int r, c;
}Tu[105][105];
int head[maxn], dis[maxn], cur[maxn], tot, S, T;
char s[10];
int rec[105][105], row[maxn], col[maxn], rn, cn;
int n, m;
void init() {
tot = 0;
memset(head, -1, sizeof(head));
memset(row, 0, sizeof(row));
memset(col, 0, sizeof(col));
memset(rec, -1, sizeof(rec));
rn = cn = 0;
}
void addEdge(int u, int v, int w) {
edge[tot].v = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot ++;
edge[tot].v = u;
edge[tot].w = 0;
edge[tot].nxt = head[v];
head[v] = tot ++;
}
bool bfs() {
memset(dis, -1, sizeof(dis));
dis[T] = 0;
queue<int> que;
que.push(T);
while(!que.empty()) {
int u = que.front(); que.pop();
for (int i = head[u]; i + 1; i = edge[i].nxt) {
if(dis[edge[i].v] == -1 && edge[i ^ 1].w > 0) {
dis[edge[i].v] = dis[u] + 1;
que.push(edge[i].v);
}
}
}
return dis[S] != -1;
}
int dfs(int u, int flow) {
if(u == T) return flow;
int delta = flow;
for (int &i = cur[u]; i + 1; i = edge[i].nxt) {
if(dis[u] == dis[edge[i].v] + 1 && edge[i].w > 0) {
int d = dfs(edge[i].v, min(delta, edge[i].w));
edge[i].w -= d; edge[i ^ 1].w += d;
delta -= d;
if(delta == 0) break;
}
}
return flow - delta;
}
int dinic() {
int ans = 0;
while(bfs()) {
for (int i = 0; i <= T; i ++)
cur[i] = head[i];
ans += dfs(S, INF);
}
return ans;
}
int GetNum(int l, int r) {
if(s[l] == 'X') return -1;
else return 100 * (s[l] - '0') + 10 * (s[l + 1] - '0') + s[l + 2] - '0';
}
int main(int argc, const char * argv[]) {
while (scanf("%d %d", &n, &m) == 2) {
init();
for (int i = 0; i < n; i ++) {
for (int j = 0; j < m; j ++) {
scanf("%s", s);
if(s[3] == 'X') continue;
if(s[3] == '.') {
Tu[i][j].r = Tu[i][j - 1].r;
Tu[i][j].c = Tu[i - 1][j].c;
row[Tu[i][j].r] --;
col[Tu[i][j].c] --;
rec[i][j] = 0;
}else {
int d1 = GetNum(0, 2), d2 = GetNum(4, 6);
if(d2 != -1) {
row[++rn] = d2; Tu[i][j].r = rn;
}
if(d1 != -1) {
col[++cn] = d1; Tu[i][j].c = cn;
}
}
}
}
S = 0; T = rn + cn + 1;
for (int i = 1; i <= rn; i ++) addEdge(S, i, row[i]);
for (int i = 1; i <= cn; i ++) addEdge(i + rn, T, col[i]);
for (int i = 0; i < n; i ++) {
for (int j = 0; j < m; j ++) {
if(rec[i][j] != -1) {
addEdge(Tu[i][j].r, Tu[i][j].c + rn, 8);
rec[i][j] = tot - 2;
}
}
}
dinic();
for (int i = 0; i < n; i ++) {
for (int j = 0; j < m; j ++) {
if(rec[i][j] == -1) printf("_");
else printf("%d", 9 - edge[rec[i][j]].w);
if(j != m - 1) printf(" ");
}
printf("\n");
}
}
return 0;
}