洛谷每日一練5.14--P2756+P4014(網絡流)

P2756

題意:

給一個二分圖要求求出最大匹配並輸出方案

思路:

用最大流解決二分圖匹配問題
ST;虛擬出源點S和匯點T;
S1;源點S向每個左點連容量爲1的邊;
S1;每個左點向源點S連一條容量爲1的反邊;
1每個左點向自己能能匹配到的右點連容量爲1的邊;
0每個右點向自己能能匹配到的左點連容量爲0的反邊;
T1;每個右點匯點T連容量爲1的邊;
T1;匯點T向每個右點連容量爲1的邊;
而對於方案,若一條由左點連向右點的邊的反向邊上有流量則選了

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
inline int read(){
	int X = 0,w = 0;char ch = 0;
	while(!isdigit(ch)) {w |= ch == '-';ch = getchar();}
	while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48),ch = getchar();
	return w ? -X : X;
}
const int N = 250;
const int inf = 0x3f3f3f3f;
struct Edge{
	int to,nex,w;
}e[N*N];
int head[N],idx = 1,dep[N];
void add_edge(int u,int v,int w){
	e[++idx].to = v;
	e[idx].w = w;
	e[idx].nex = head[u];
	head[u] = idx;
}

int n,m,S,T;
bool bfs(){
	memset(dep,0,sizeof(dep));
	dep[S] = 1;
	queue<int> q;
	q.push(S);
	while(q.size()){
		int u = q.front();q.pop();
		for(int i = head[u];~i;i = e[i].nex){
			int v = e[i].to,w = e[i].w;
			if(w && !dep[v]){
				dep[v] = dep[u] + 1;
				q.push(v);
			}
		}
	}
	return dep[T];
}
int dfs(int u,int flow){
	if(u == T) return flow;
	int sum = 0;
	for(int i = head[u];~i;i = e[i].nex){
		int v = e[i].to,w = e[i].w;
		if(w && dep[v] == dep[u] + 1){
			int t = dfs(v,min(flow,w));
			flow -= t,sum += t;
			e[i].w -= t,e[i^1].w += t;
		}
	}
	if(!sum) dep[u] = 0;
	return sum;
}
int main(){
	memset(head,-1,sizeof(head));
	scanf("%d%d",&m,&n);
	S = n + 1,T = n + 2;//將源點設爲n+1,匯點設爲n+2 
	int u,v;
	while(1){
		u = read(),v = read();
		if(u == -1) break;
		add_edge(u,v,1),add_edge(v,u,0); 
	}
	for(int i = 1;i <= m;i++){
		add_edge(S,i,1),add_edge(i,S,0);
	}
	for(int i = m + 1;i <= n;i++){
		add_edge(i,T,1),add_edge(T,i,0);
	}
	int ans = 0;
	while(bfs()) ans += dfs(S,inf);
	printf("%d\n",ans);
	for(int i = 2;i <= idx;i+=2){
		if(e[i].to != S&&e[i^1].to != S)
		if(e[i].to != T&&e[i^1].to != T)
		if(e[i^1].w != 0){
			printf("%d %d\n",e[i^1].to,e[i].to);   	
		}
	}
	return 0;
}

P4014

題意:

給一個二分圖,每個匹配有其價值
求價值最高的完美匹配和價值最低的完美匹配

思路:

費用流,跑一遍最小費用最大流和最大費用最大流

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
using namespace std;
inline int read(){
	int X = 0,w = 0;char ch = 0;
	while(!isdigit(ch)) {w |= ch == '-';ch = getchar();}
	while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48),ch = getchar();
	return w ? -X : X;
}
const int N = 210,inf = 0x3f3f3f3f;
int n,head[N],dist[N];
int q[N*100],l,r;
int idx,S,T;
int maxflow = 0,mincost = 0;
int mp[N][N];
bool vis[N];
struct node{
    int to,nex,w,cost;
}e[N*N*2];
inline void add(int u,int v,int w,int c) {
    ++idx;
    e[idx].to=v;e[idx].w=w;e[idx].cost=c;e[idx].nex=head[u];head[u]=idx;
    ++idx;
    e[idx].to=u;e[idx].w=0;e[idx].cost=-c;e[idx].nex=head[v];head[v]=idx;
}
bool spfa(){
    memset(vis,0,sizeof(vis));
    memset(dist,0x3f,sizeof(dist));
    l = 1;r = 0;
    queue<int> q;q.push(S);
    dist[S]=0; vis[S]=1;
    while (q.size()) {
        int u = q.front();q.pop();
        vis[u] = 0;
        for (int i = head[u];~i;i = e[i].nex) {
            int v = e[i].to;
            if (e[i].w && dist[v]>dist[u]+e[i].cost) {
                dist[v] = dist[u]+e[i].cost;
                if (!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    return dist[T] < inf;
}
int dfs(int u,int flow) {
    if (u == T) {
        vis[T]=1;
        maxflow += flow;
        return flow;
    }
    int goflow = 0,used = 0;
    vis[u]=1;
    for (int i = head[u];~i;i = e[i].nex) {
        int v = e[i].to;
        if ((!vis[v] || v == T) && e[i].w && dist[v]==dist[u]+e[i].cost) {
            goflow = dfs(v,min(flow-used,e[i].w));
            if (!goflow) continue;
            used += goflow;
            e[i].w -= goflow;
            e[i^1].w += goflow;
            mincost += goflow*e[i].cost;
            if (used == flow) break;
        }
    }
    return used;
}
void MCMF(){ 
    while (spfa()) {
        vis[T]=1;
        while (vis[T]) {
            memset(vis,0,sizeof(vis));
            dfs(S,inf);
        }
    }
}
int a=0;
int main(){
	memset(head,-1,sizeof(head));idx = 1;
    n = read();
    S = 0;
    T = 2*n+1;
    for (int i = 1;i <= n;++i) {
        add(S,i,1,0);
        add(i+n,T,1,0);
        for (int j = 1;j <= n;++j) {
            mp[i][j] = read();
            add(i,j+n,1,-mp[i][j]);
        }
    }
    MCMF();
    int mx = -mincost;
    mincost = maxflow = 0;
    idx = 1;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
    for (int i = 1;i <= n;++i) {
        add(S,i,1,0);
        add(i+n,T,1,0);
        for (int j = 1;j <= n;++j) {
            add(i,j+n,1,mp[i][j]);
        }
    }
    MCMF();
    printf("%d\n%d\n",mincost,mx);
    return 0;
}

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