Codeforces 546E Soldier and Traveling 最大流 C#實現

題意

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章