题意
- 在某个国家有n个城市,他们通过m条无向的道路相连。每个城市有一支队伍。第i个城市的队伍有ai个队员。现在队员开始移动。每个队员可以呆在原地,或者走到和他所在城市直接相邻的城市
- 判断移动之后,能不能使得第i个城市恰好有bi个队员。若可以,需给出移动方式
思路
- 将源点与各个点相连,容量就是a[i]。
- 将汇点与各个点相连,容量就是b[i]。
- 将i与i+n相连,容量是inf,表示队员可以留在自己的城市里面。
- 对于两个城市i与j有边的,将i与j+n相连,将j与i+n相连,容量均为inf,表示队员可以移动
- 最大流,判断是否等于sum_a 和 sum_b,不是为no,是为yes
- 若是yes,通过图中加入的反向边流量可以得出队员如何移动。
实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DTATest
{
class Program
{
static int n, m, suma = 0, sumb = 0;
static MaxFlow mf;
static int[] a = new int[105];
static int[] b = new int[105];
const int MAX = 300;
static void Main(string[] args)
{
var str = Console.ReadLine().Split(' ');
n = Int32.Parse(str[0]);
m = Int32.Parse(str[1]);
mf = new MaxFlow(MAX);
mf.init(n * 2 + 2);
var stra = Console.ReadLine().Split(' ');
var strb = Console.ReadLine().Split(' ');
for (int i = 0; i < n; i++)
{
a[i] = Int32.Parse(stra[i]);
b[i] = Int32.Parse(strb[i]);
suma += a[i];
sumb += b[i];
mf.add_edge(0, i + 1, a[i]);
mf.add_edge(n + i + 1, mf.V - 1, b[i]);
mf.add_edge(i + 1, n + i + 1, MaxFlow.INF);
}
for (int i = 0; i < m; i++)
{
str = Console.ReadLine().Split(' ');
mf.add_edge(Int32.Parse(str[0]), Int32.Parse(str[1]) + n, MaxFlow.INF);
mf.add_edge(Int32.Parse(str[1]), Int32.Parse(str[0]) + n, MaxFlow.INF);
}
if (mf.max_flow(0, mf.V - 1) == suma && sumb == suma)
{
Console.WriteLine("YES");
for (int i = 0; i < n; i++)
{
int[] tmp = new int[n];
//通过i号点的边的反向边来得到流量
for (int j = 0; j < mf.G[i + 1].Count; j++)
{
int v = mf.G[i + 1][j].to - n - 1;
int vid = mf.G[i + 1][j].to;
//如果是反向边,则跳过
if (vid == 0)
continue;
int eid = mf.G[i + 1][j].rev;
tmp[v] = mf.G[vid][eid].cap;
}
for (int j = 0; j < n - 1; j++)
{
Console.Write(tmp[j] + " ");
}
Console.WriteLine(tmp.Last());
}
}
else
{
Console.WriteLine("NO");
}
//Console.Read();
}
}
/// <summary>
/// 实现最大流的类,需实例化使用
/// </summary>
public class MaxFlow
{
#region 内部类定义
/// <summary>
/// 最大流边结构定义
/// </summary>
public class edge
{
public int to, cap, rev;
public edge(int to, int cap, int rev)
{
this.to = to;
this.cap = cap;
this.rev = rev;
}
}
#endregion
#region 变量定义
/// <summary>
/// 最大节点数,可略大于真实节点数,以防访问越界
/// </summary>
private int MAX_V;
/// <summary>
/// 设置无穷大值
/// </summary>
public const int INF = 0x3f3f3f3f;
/// <summary>
/// 节点数
/// </summary>
public int V;
/// <summary>
/// 图的结构
/// </summary>
public List<edge>[] G;
/// <summary>
/// 顶点到源点的距离标号
/// </summary>
public int[] level;
/// <summary>
/// 当前弧,在其之前的边已经没有用了
/// </summary>
public int[] iter;
#endregion
#region 构造函数
public MaxFlow(int MAX_V)
{
this.MAX_V = MAX_V;
V = 0;
G = new List<edge>[this.MAX_V];
for (int i = 0; i < G.Length; i++)
{
G[i] = new List<edge>();
}
level = new int[this.MAX_V];
iter = new int[this.MAX_V];
}
#endregion
#region 公有函数
/// <summary>
/// 加边前先初始化
/// </summary>
/// <param name="n">节点数量</param>
public void init(int n)
{
for (int i = 0; i < V; i++)
{
G[i].Clear();
}
V = n;
}
/// <summary>
/// 添加一条边
/// </summary>
/// <param name="from">起点</param>
/// <param name="to">终点</param>
/// <param name="cap">容量</param>
public void add_edge(int from, int to, int cap)
{
G[from].Add(new edge(to, cap, G[to].Count));
G[to].Add(new edge(from, 0, G[from].Count - 1));
}
/// <summary>
/// 求解从s到t的最大流
/// </summary>
public int max_flow(int s, int t)
{
int flow = 0;
for (; ; )
{
bfs(s);
if (level[t] < 0)
return flow;
fill(iter, 0);
int f;
while ((f = dfs(s, t, INF)) > 0)
{
flow += f;
}
}
}
#endregion
#region 私有方法
private void fill(int[] a, int val)
{
for (int i = 0; i < a.Length; i++)
{
a[i] = val;
}
}
/// <summary>
/// 通过DFS寻找增广路
/// </summary>
private int dfs(int v, int t, int f)
{
if (v == t)
return f;
for (int i = iter[v]; i < G[v].Count; i++)
{
if (G[v][i].cap > 0 && level[v] < level[G[v][i].to])
{
int d = dfs(G[v][i].to, t, Math.Min(f, G[v][i].cap));
if (d > 0)
{
G[v][i].cap -= d;
G[G[v][i].to][G[v][i].rev].cap += d;
return d;
}
}
}
return 0;
}
/// <summary>
/// 通过BFS计算从源点出发的距离标号
/// </summary>
void bfs(int s)
{
fill(level, -1);
Queue<int> que = new Queue<int>();
level[s] = 0;
que.Enqueue(s);
while (que.Count > 0)
{
int v = que.Dequeue();
for (int i = 0; i < G[v].Count; i++)
{
edge e = G[v][i];
if (e.cap > 0 && level[e.to] < 0)
{
level[e.to] = level[v] + 1;
que.Enqueue(e.to);
}
}
}
}
#endregion
}
}