題意
- 在某個國家有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
}
}