浅谈费用流

时间:2024-03-12 06:58:36

\(SAP\)

\(\mathcal{No.1} 方法及证明\)

\(SSP算法是一个贪心的算法。它的思路是每次寻找单位费用最小的增广路进行增广,直到图上不存在增广路为止。\)

\(如果图上存在单位费用为负的圈,SSP 算法正确无法求出该网络的最小费用最大流。此时需要先使用消圈算法消去图上的负圈。\)

\(同dinic一样,这里的增广路的长度是单调不递减的\)

\(这样找能够保证最大流,但需证明一定是最小费用\)

\(引理:当流量为i时,且图中不存在负环,那么此时是流量为i时最小费用\)

\(考虑对于流量为i的f_i及其i+1的f_{i+1}\)

\(假设f_i为最小费用并且f_{i+1}为f_i用最短路增广出的流\)

\(假设存在f_{i+1}'为f_i增广出的流比f_i更小\)

\(\therefore f_{i+1}'的增广路径小于f_{i+1}\)

\(\therefore f_{i+1}'的增广路径中有负环,这与其矛盾\)

\(回到其最开始的证明,即最短路增广的正确性\)

\(设f_i为第i次增广的流\)

\(假设存在f_i',使得|f'_i|=|f_i|且f'_i的花费小于f_i的花费\)

\(由于|f_{i-1}|<|f'_{i}|,因此一定存在增广路于f_{i-1}到f'_{i}\)

\(又由于f'_i的花费小于f_i的花费,f_i是最短路增广\)

\(所以f'_i的增广路径存在负环,于引理矛盾,因此假设不成立\)

\(\mathcal{No.2} 例题\)

P4134 [BJOI2012]连连看

\(给每一个满足条件的x,y连边,可以发现在1000以内是一个二分图,跑最大费用流即可\)

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 6005;
const int MAXM = 50005;
int n, m;
int x, y, z, c;
struct Edge {
    int to, nex;
    int val;
    int cost;
} edge[MAXM * 2];
int cnt = 1;
int head[MAXN];
void Add(int u, int v, int w, int cost) {
    edge[++cnt].to = v;
    edge[cnt].nex = head[u];
    edge[cnt].val = w;
    edge[cnt].cost = -cost;
    head[u] = cnt;
}

int dis[MAXN];
int vis[MAXN];
int arc[MAXN];
int s, t;
int Energy[MAXN];
bool spfa() {
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    queue<int>q;

    q.push(s);
    dis[s] = 0;
    vis[s] = 1;

    while (q.size()) {
        int temp = q.front();
        q.pop();
        vis[temp] = 0;
        arc[temp] = head[temp];

        for (int i = head[temp]; i; i = edge[i].nex) {
            int v = edge[i].to;
            int w = edge[i].cost;

            if (!edge[i].val) {
                continue;
            }

            if (dis[v] > dis[temp] + w) {
                dis[v] = dis[temp] + w;

                if (!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }

    memset(vis, 0, sizeof(vis));

    if (dis[t] == 0x3f3f3f3f) {
        return 0;
    }

    return 1;

}
int mincost = 0;
int maxflow = 0;
int dfs(int x, int flow) {
    if (x == t || flow == 0) {
        return flow;
    }

    int used = 0;
    vis[x] = 1;

    for (int i = arc[x]; i; i = edge[i].nex) {

        int v = edge[i].to;
        int w = edge[i].cost;
        if (vis[v]) {
            continue;
        }

        if (!edge[i].val) {
            continue;
        }

        if (dis[x] + w == dis[v]) {
            arc[x] = i;
            int nowu = dfs(v, min(flow - used, edge[i].val));
            used += nowu;

            edge[i].val -= nowu;
            edge[i ^ 1].val += nowu;
            mincost += nowu * w;

            if (used == flow) {
                break;
            }
        }
    }

    vis[x] = 0;
    return used;
}
struct node{
	int u,val;
	bool operator<(const node x)const{
		return val>x.val;
	}
};
bool dijkstra()
{
	
	for(int i=0;i<=n+50;i++)
	{
		dis[i]=0x3f3f3f3f;
		vis[i]=0;
		 
	}
	dis[s]=0;
	arc[s]=head[s];
	priority_queue<node>q;
	node gsg;
	gsg.u=s;
	gsg.val=0;
	q.push(gsg);
	while(q.size())
	{
		node temp=q.top();
		q.pop();
		if(vis[temp.u])
		{
			continue;
		}
		vis[temp.u]=1;
		arc[temp.u]=head[temp.u];
		for(int i=head[temp.u];i;i=edge[i].nex)
		{
			int v=edge[i].to;
			int w=Energy[temp.u]-Energy[v]+edge[i].cost;//保证无负权 
			if(!edge[i].val)
			{
				continue;
			}
			if(dis[v]>dis[temp.u]+w)
			{
				dis[v]=dis[temp.u]+w;
				node gaf;
				gaf.val=dis[v];
				gaf.u=v;
				q.push(gaf);
			}
		}
	}
	for(int i = 0; i <= n+50; i++)
	{
 		dis[i]=dis[i]-Energy[s]+Energy[i];//势能函数的更新要累加当前的 
    }
    for(int i = 0; i <= n+50; i++)
    {
    	Energy[i] = dis[i];
	}
        

	memset(vis,0,sizeof(vis));
	if(dis[t]>=0x3f3f3f3f)
	{
		return 0;
	}
	return 1;
 } 
pair<int, int>dinic() {
	mincost=0;
	maxflow=0;
    if(!spfa())
    {
    	return make_pair(maxflow,mincost);
	}
	for(int i=0;i<=n+50;i++)
	{
		Energy[i]=dis[i];
	}//这里清空要注意范围 
	while(dijkstra())
	{
	//	printf("fiuck");
		maxflow+=dfs(s,INF);
		
	}
	return make_pair(maxflow,mincost);
	
}
int clor[MAXN];
vector<int>g[MAXN];
bool is2(int x)
{
	if(int(sqrt(x))==sqrt(x))
	{
		return 1;
	}
	return 0;
 } 
 int gcd(int a,int b){
 	if(!b)
 	{
 		return a;
	 }
	 return gcd(b,a%b);
 }
 void Dfs(int x,int clo)
 {
 	if(clor[x])
 	{
 		return;
	 }
	 clor[x]=clo;
	 for(int i=0;i<g[x].size();i++)
	 {
	 	int v=g[x][i];
	 	Dfs(v,clo==1?2:1);
	 }
 }
int main() {
	scanf("%d %d",&m,&n);
	for(int i=m;i<=n;i++)
	{
		for(int j=m+1;j<=n;j++)
		{
			if(is2(j*j-i*i))
			{
				//printf("%d %d\n",i,j);
				if(gcd(i,sqrt(j*j-i*i))==1)
				{
					g[i].push_back(j);
					g[j].push_back(i); 
					
				}
			}
		}	
	}    
	for(int i=m;i<=n;i++)
	{
		if(!clor[i])
		{
			Dfs(i,1);
		}
	}
	for(int i=m;i<=n;i++)
	{
		if(clor[i]==1)
		{
			Add(0,i-m+1,1,0);
			Add(i-m+1,0,0,0);
			for(int j=0;j<g[i].size();j++)
			{
				int v=g[i][j];
				Add(i-m+1,v-m+1,1,i+v);
				Add(v-m+1,i-m+1,0,-(i+v));
			}
		}
		else
		{
			Add(i-m+1,n-m+2,1,0);
			Add(n-m+2,i-m+1,0,0);
		}
	}
	s=0;
	t=n-m+2;
	pair<int,int>pi=dinic();
	printf("%d %d",pi.first,pi.second*-1);
}
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 4005;
const int MAXM = 50005;
int n, m;
int x, y, z, c;
struct Edge {
    int to, nex;
    int val;
    int cost;
} edge[MAXM * 2];
int cnt = 1;
int head[MAXN];
void Add(int u, int v, int w, int cost) {
    edge[++cnt].to = v;
    edge[cnt].nex = head[u];
    edge[cnt].val = w;
    edge[cnt].cost = cost;
    head[u] = cnt;
}

int dis[MAXN];
int vis[MAXN];
int arc[MAXN];
int s, t;

bool spfa() {
    for(int i=s;i<=t;i++)
    {
    	dis[i]=-0x3f3f3f3f;
	}
    memset(vis, 0, sizeof(vis));
    queue<int>q;

    q.push(s);
    dis[s] = 0;
    vis[s] = 1;

    while (q.size()) {
        int temp = q.front();
        q.pop();
        vis[temp] = 0;
        arc[temp] = head[temp];

        for (int i = head[temp]; i; i = edge[i].nex) {
            int v = edge[i].to;
            int w = edge[i].cost;

            if (!edge[i].val) {
                continue;
            }

            if (dis[v] < dis[temp] + w) {
                dis[v] = dis[temp] + w;

                if (!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }

    memset(vis, 0, sizeof(vis));

    if (dis[t] == -0x3f3f3f3f) {
        return 0;
    }

    return 1;

}
int mincost = 0;
int maxflow = 0;
int dfs(int x, int flow) {
    if (x == t || flow == 0) {
        return flow;
    }

    int used = 0;
    vis[x] = 1;

    for (int i = arc[x]; i; i = edge[i].nex) {

        int v = edge[i].to;
        int w = edge[i].cost;

        if (vis[v]) {
            continue;
        }

        if (!edge[i].val) {
            continue;
        }

        if (dis[x] + w == dis[v]) {
            arc[x] = i;
            int nowu = dfs(v, min(flow - used, edge[i].val));
            used += nowu;

            edge[i].val -= nowu;
            edge[i ^ 1].val += nowu;
            mincost += nowu * w;

            if (used == flow) {
                break;
            }
        }
    }

    vis[x] = 0;
    return used;
}
pair<int, int>dinic() {
    maxflow = 0;
    mincost = 0;
    int flow = 0;

    while (spfa()) {
        maxflow += dfs(s, INF);
    }

    return make_pair(maxflow, mincost);
}
int clor[MAXN];
vector<int>g[MAXN];
bool is2(int x)
{
	if(int(sqrt(x))==sqrt(x))
	{
		return 1;
	}
	return 0;
 } 
 int gcd(int a,int b){
 	if(!b)
 	{
 		return a;
	 }
	 return gcd(b,a%b);
 }
 void Dfs(int x,int clo)
 {
 	if(clor[x])
 	{
 		return;
	 }
	 clor[x]=clo;
	 for(int i=0;i<g[x].size();i++)
	 {
	 	int v=g[x][i];
	 	Dfs(v,clo==1?2:1);
	 }
 }
int main() {
	scanf("%d %d",&m,&n);
	for(int i=m;i<=n;i++)
	{
		for(int j=m+1;j<=n;j++)
		{
			if(is2(j*j-i*i))
			{
				//printf("%d %d\n",i,j);
				if(gcd(i,sqrt(j*j-i*i))==1)
				{
					g[i].push_back(j);
					g[j].push_back(i); 
					
				}
			}
		}	
	}    
	for(int i=m;i<=n;i++)
	{
		if(!clor[i])
		{
			Dfs(i,1);
		}
	}
	for(int i=m;i<=n;i++)
	{
		if(clor[i]==1)
		{
			Add(0,i-m+1,1,0);
			Add(i-m+1,0,0,0);
			for(int j=0;j<g[i].size();j++)
			{
				int v=g[i][j];
				Add(i-m+1,v-m+1,1,i+v);
				Add(v-m+1,i-m+1,0,-(i+v));
			}
		}
		else
		{
			Add(i-m+1,n-m+2,1,0);
			Add(n-m+2,i-m+1,0,0);
		}
	}
	s=0;
	t=n-m+2;
	pair<int,int>pi=dinic();
	printf("%d %d",pi.first,pi.second);
}