题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4975
题意:
现有一个n * m的矩阵,矩阵的每个元素都是0~9之间的一个个位数。
给出矩阵每一行和每一列的和。
求能否构建出这个矩阵以及解的唯一性。
算法:
典型的网络流问题。
把每一行、每一列都当做一个点。
由源点向每一行连一条边,容量为这一行的和。
由每一列向汇点连一条边,容量为这一列的和。
由每一行向每一列连一条边,容量为9:
这条边的流量就代表这一行和这一列交叉处的这个元素的大小,容量限制了这个元素在0~9之间。
最后如果所有由源点流出的边都满流且所有流向汇点的边也满流,即为有解。
判断解的唯一性即判断最大流的唯一性,充要条件为残余网络中没有长度大于2的环,可以用类似tarjan的dfs来判断。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <climits>
#include <cmath>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 10000;
const int maxm = 1000000;
int to[maxm], nxt[maxm];
int cap[maxm];
int head[maxn], cur[maxn], Q[maxn], dep[maxn];
int vis[maxn];
int E;
void _addedge(int u, int v, int w)
{
to[E] = v;
cap[E] = w;
nxt[E] = head[u];
head[u] = E ++;
}
void addedge(int u, int v, int w)
{
_addedge(u, v, w);
_addedge(v, u, 0);
}
bool bfs(int S, int T)
{
memset(dep, -1, sizeof(dep));
dep[T] = 0;
int front = 0, rear = 0;
Q[rear ++] = T;
while (front != rear && dep[S] == -1)
{
int u = Q[front ++];
for (int i = head[u]; i != -1; i = nxt[i])
{
int v = to[i];
if (cap[i ^ 1] && dep[v] == -1)
{
dep[v] = dep[u] + 1;
Q[rear ++] = v;
}
}
}
return dep[S] != -1;
}
int dfs(int S, int T, int lim)
{
if (S == T)
{
return lim;
}
int tmp = lim;
for (int &i = cur[S]; i != -1; i = nxt[i])
{
int v = to[i];
if (cap[i] && dep[S] == dep[v] + 1)
{
int ret = dfs(v, T, min(tmp, cap[i]));
tmp -= ret;
cap[i] -= ret;
cap[i ^ 1] += ret;
}
if (!tmp)
{
break;
}
}
return lim - tmp;
}
int dinic(int S, int T, int n)
{
int ans = 0;
while (bfs(S, T))
{
for (int i = 0; i < n; i ++)
{
cur[i] = head[i];
}
ans += dfs(S, T, INT_MAX);
}
return ans;
}
void init()
{
E = 0;
memset(head, -1, sizeof(head));
}
void dfs0(int u, int tot, int p, bool &flg)
{
if (vis[u] != -1 && vis[u] != tot)
{
return;
}
if (vis[u] == tot)
{
flg = true;
}
if (flg)
{
return;
}
vis[u] = tot;
for(int i = head[u]; i != -1; i = nxt[i])
{
int v = to[i];
if(cap[i] && v != p)
{
dfs0(v, tot, u, flg);
}
}
}
int main()
{
int cas;
scanf("%d", &cas);
for (int Tcot = 1; Tcot <= cas; Tcot ++)
{
int n, m;
scanf("%d %d", &n, &m);
init();
int S = 0, T = n + m + 1;
int allSum = 0;
for (int i = 0; i < n; i ++)
{
int sum;
scanf("%d", &sum);
addedge(S, i + 1, sum);
allSum += sum;
}
for (int i = 0; i < m; i ++)
{
int sum;
scanf("%d", &sum);
addedge(n + i + 1, T, sum);
}
for (int i = 0; i < n; i ++)
{
for (int j = 0; j < m; j ++)
{
addedge(i + 1, n + j + 1, 9);
}
}
printf("Case #%d: ", Tcot);
if (dinic(S, T, n + m + 2) != allSum)
{
puts("So naive!");
continue;
}
bool flg = false;
memset(vis, -1, sizeof(vis));
if ((allSum > 0) && (allSum != n * m * 9))
{
for (int i = 0; (!flg) && (i < n + m + 2); i ++)
{
if (vis[i] == -1)
{
dfs0(i, i, -1, flg);
}
}
}
if (flg)
{
puts("So young!");
}
else
{
puts("So simple!");
}
}
return 0;
}