1. 程式人生 > 實用技巧 >C語言之switch語句

C語言之switch語句

網路流

網路:有向圖,有一個入度為0的點,有一個出度為0的點

源點:入度為0的點s

匯點:出度為0的點t

容量:每條邊的權值c(u,v)=3

流量:f(s,a)<=c(u,v)(容量限制(Capacity Constraint):對所有頂點對 u, v ∈ V,要求 f(u, v) ≤ c(u, v)。)

反對稱性(Skew Symmetry):對所有頂點對 u, v ∈ V,要求 f(u, v) = - f(v, u)。

流入量:對於c來說 f(a,c)+f(b,c)

|| 流守恆性:任意u,存在 ∑ f(i,u)= ∑ f(u,j)

流出量:對於c來說 f(c,t)

總流量:|f|= ∑ f(s,v)(與s直接相連的點)

最小流:一定是0

最大流:著重討論的問題: 給出源點 s 和匯點 t 的流網路 G,希望找出從 s 到 t 的最大值流。

割:斷開後可以使s與t不連通的邊的集合 |cut|=割的邊值之和

最大割:等於全部邊值之和

最小割:著重要討論的問題

費用流:在最大流的情況下討論費用

殘留網路: 殘留量(c'(u,v)=c(u,v)-f(u,v))組成的網路

增廣路:能夠增加流量的路(s-t)

限制條件: 經過邊的流不能超過邊的容量;
除了源點 s 和匯點 t,對於其它所有頂點,流入量與流出量要相等。

FF演算法

Ford-Fulkerson 演算法( 即增廣路方法 簡稱FF方法 )是一種解決最大流的方法,其依賴於三種重要思想:
殘留網路(Residual networks)
增廣路徑(Augmenting paths)
割(Cut)

網路達到最大流當且僅當殘留網路中沒有增廣路

HDU - 1532 https://vjudge.net/problem/HDU-1532

#include <queue>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 205
#define INF 1e9
//最大流板子
int n,m,a,b,cost,map[maxn][maxn];//儲存網路
int max_flow(int num,int map[][maxn],int s,int t)//最大流函式(結點數,圖,源點,匯點)
{
    int p[maxn],min_flow[maxn],flow[maxn][maxn],ans = 0 ;//記錄結點的父節點  當前路徑中最小的一段的值(限制值)  記錄當前網路中的流  結果
    memset(flow,0,sizeof(flow));
    while(1)//一直迴圈,直到不存在增廣路徑
    {
        queue<int> q;
        memset(p,-1,sizeof(p));
        q.push(s);
        p[s] = -2;//源點父節點
        min_flow[s] = INF;
        while(!q.empty())//BFS   尋找增廣路徑
        {
            int temp = q.front();//出列
			q.pop();
            for(int i = 0 ; i < num ; i++)//從temp往外擴充套件
            {
                if(p[i] == -1 && flow[temp][i] < map[temp][i])
						//當結點i還未被探索到且還有可用流量
                {
                    q.push(i);//加入佇列
                    p[i] = temp;//父節點
                    min_flow[i] = min(min_flow[temp],map[temp][i]-flow[temp][i]);
                }
            }
            if(p[t]!=-1)//t的父節點不=初始值,說明已經BFS到了一條路徑
            {
                int k=t;
                while(p[k] >= 0)
                {flow[p[k]][k] +=min_flow[t]; flow[k][p[k]] -=min_flow[t];k = p[k];}//新流量加入flow
                break;
            }
        }
        if(p[t] != -1)ans+=min_flow[t];
        else return ans;//若不存在增廣路徑則返回
    }
}
int main()
{
    //n流通數 m節點數
    while(cin>>n>>m)
    {
        memset(map,0,sizeof(map));//清空
        for(int i=0;i<n;i++)
        {
			cin>>a>>b>>cost;
            map[a-1][b-1]+=cost;//存圖
        }
        cout<<max_flow(m,map,0,m-1)<<endl;
    }
    return 0;
}

EK演算法

Edmonds-Karp演算法 即最短路徑增廣演算法 簡稱EK演算法

在原先每條邊的基礎上,加上相同容量的反向邊

BFS找增廣路:找到:更新最大流+更新參與網路

​ 找不到:退出

不斷的找最短路 找的方法就是每次找一條邊數最少的增廣 也就是最短路徑增廣

HDU - 1532 https://vjudge.net/problem/HDU-1532

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<stdio.h>
#include<cstring>
using namespace std;
const int maxn=220;
const int inf=1e9;
//EK演算法
int n,m,mp[maxn][maxn],flow[maxn],pre[maxn];//n點數 m邊數 map存圖 flow表示當前流量 pre儲存前一條增廣路
queue<int> q;//因為要用BFS所以需要佇列

int bfs(int s,int t)
{
    while(!q.empty())q.pop();
    memset(pre,-1,sizeof(pre));
    pre[s]=0;flow[s]=inf;
    q.push(s);
    while (!q.empty())
    {
        int p=q.front();q.pop();
        if(p==t)//走到匯點
            break;
        for(int i=1;i<=n;i++)//找邊
        {

            if(i!=s&&mp[p][i]>0&&pre[i]==-1)
            {
                pre[i]=p;
                flow[i]=min(flow[p],mp[p][i]);
                q.push(i);
            }
        }
    }
    if(pre[t]==-1)return -1;
    return flow[t];//流量是增加的差值
}

int EK(int s,int t)
{
    int delta=0,tol=0;
    while (1)
    {
        delta=bfs(s,t);
        if(delta==-1)break;
        int p=t;
        while(p!=s)
        {
            mp[pre[p]][p]-=delta;
            mp[p][pre[p]]+=delta;
            p=pre[p];
        }
        tol+=delta;
    }
    return tol;
}

int main()
{
    while(cin>>m>>n)
    {
        memset(mp,0,sizeof(mp));
        memset(flow,0,sizeof(flow));
        for(int i=0;i<m;i++)
        {
            int u,v,w;cin>>u>>v>>w;
            mp[u][v]+=w;
        }
        cout<<EK(1,n)<<endl;
    }
   return 0;
}

最小費用最大流問題

通過EK,Dinic,ISAP演算法可以得到網路流圖中的最大流,一個網路流圖中最大流的流量max_flow是唯一的,但是達到最大流量max_flow時每條邊上的流量分配f是不唯一的。
如果給網路流圖中的每條邊都設定一個費用cost,表示單位流量流經該邊時會導致花費cost。那麼在這些流量均為max_flow的流量分配f中,存在一個流量總花費最小的最大流方案。
min{sum(cost(i, j)*f(i,j) | (i, j)屬於方案f中的邊, f(i,j)為 邊(i,j)上的流量, f為某一個最大流方案}。此即為最小費用最大流

最小費用最大流問題與演算法實現(Bellman-Ford、SPFA、Dijkstra)

例題:

POJ - 2135 https://vjudge.net/problem/POJ-2135

#include<stdio.h>
#include<string.h>
#include<queue>
#include<set>
#include<iostream>
#include<map>
#include<stack>
#include<cmath>
#include<algorithm>
#define ll long long
#define mod 1000000007
#define eps 1e-8
using namespace std;
const int MAXN = 10000;
const int inf = 0x3f3f3f3f;
struct Edge {
	int to,next,cap,flow,cost;
} edge[100000];
int N,head[MAXN],tol,pre[MAXN],dis[MAXN];
bool vis[MAXN];
void adde(int u,int v,int cap,int cost)
{
	edge[tol].to = v;edge[tol].cap = cap;edge[tol].cost = cost;edge[tol].flow = 0;edge[tol].next = head[u];
	head[u] = tol++;
	edge[tol].to = u;edge[tol].cap = 0;edge[tol].cost = -cost;edge[tol].flow = 0;edge[tol].next = head[v];
	head[v] = tol++;
}
bool spfa(int s,int t)
{
	queue<int>q;
	for(int i = 0; i < N+1; i++){dis[i] = inf;vis[i] = false;pre[i] = -1;}
	dis[s] = 0;vis[s] = true;
	q.push(s);
	while(!q.empty())
    {
		int u = q.front();
		q.pop();
		vis[u] = false;
		for(int i = head[u]; i != -1; i = edge[i].next)
        {
			int v = edge[i].to;
			if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost )
            {
				dis[v] = dis[u] + edge[i].cost;
				pre[v] = i;
				if(!vis[v])
                {
					vis[v] = true;
					q.push(v);
				}
			}
		}
	}
	if(pre[t] == -1)return false;
	else return true;
}

int mincostmaxflow(int s,int t,int &cost) {
	int flow = 0;
	cost = 0;
	while(spfa(s,t)) {
		int Min = inf;
		for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
			if(Min > edge[i].cap - edge[i].flow)
				Min = edge[i].cap - edge[i].flow;
		}
		for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
			edge[i].flow += Min;
			edge[i^1].flow -= Min;
			cost += edge[i].cost * Min;
		}
		flow += Min;
		if(flow==2)
		return flow;
	}
	return flow;
}
int main()
{
	int n,m;
	cin>>n>>m;
	N = n,tol = 0;
	memset(head,-1,sizeof(head));
	for(int i=0;i<m;i++)
	{
		int u,v,w;
		cin>>u>>v>>w;
		adde(u,v,1,w);
		adde(v,u,1,w);
	}
	int c;
	mincostmaxflow(1,n,c);
	cout<<c<<endl;
	return 0;
}

//最大費用最小流只要在新增邊的時候換一下位置就好了
//求最大費用最大流只需要把費用換成相反數,用最小費用最大流求解即可