Luogu3410 & 2762 - 最小割 -

题目链接:https://www.luogu.com.cn/problem/P3410

题解:
建图就形如这样的:

其中左边的点表示客户要求,右边的点表示下属
S -> 左边点断一条边,就说明dismiss这个要求, 右边点 -> T 断一条边,就说明用了这个下属(注意二者意义是反过来的)
答案就是客户给的钱 - 最小割
直观上理解:左边断边,对应的割中加上了这个权值,答案中少了这个,也就是说不用这个客户之后就没有客户给的钱了。右边断边,对应的割中加上权值,答案中额外减去了这个断边,也就是说用了这个下属得给这人钱.这样就能构成答案了

2762中还需要我们输出方案。联想dinic的原理,最终一次bfs之后\(d[]\)有值的都是割完后和源点在同一个连通块内的点,又因为上面所说的,左边断边意味着不用这个客户,因此在连通块内意味着用这个客户,即为答案所求,同理可推右边也一样。

3410

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <cassert>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;
#define int LL

const int inf = 1e18, INF = 0x3f3f3f3f, maxn = 200005;

int n,m,s,t;
struct ed{
	LL from,to,cap,flow,rev;
	ed(){}
	ed(LL from,LL to,LL cap,LL flow,LL rev):from(from),to(to),cap(cap),flow(flow),rev(rev){}
};
vector<ed>g[maxn];

struct netflow{
	int cur[maxn]; 
	int d[maxn], q[maxn], hd, tl;
	int s, t;	// 源 汇 
	
	netflow(){s=t=-1;}
	
	void init(int s0,int t0){
		s = s0, t = t0;
	}

	void add(int x,int y,int v){
		g[x].push_back(ed(x,y,v,0,g[y].size()));
		g[y].push_back(ed(y,x,0,0,g[x].size() - 1));
	}
	
	int bfs(){
		memset(d,0, sizeof d);
		hd = tl = 0;
		q[tl ++] = s;
		d[s] = 1;
		while(hd != tl){
			int now = q[hd ++];
			for(int i = 0;i<g[now].size();i++){
				ed &e = g[now][i];
				if(!d[e.to] && e.cap > e.flow)d[e.to] = d[now] + 1, q[tl ++] = e.to;
			}
		}
		return d[t];
	}
	
	LL dfs(int now,LL rem){	// rem 当前流量 
		if(now == t || !rem)return rem;
		LL flow = 0;
		for(int &i = cur[now]; i < g[now].size();i ++){
			ed &e = g[now][i];
				// 分层图 & 残量不为0 
			if(d[e.to] == d[now] + 1 && e.cap > e.flow){
				LL f = dfs(e.to, min(rem, e.cap - e.flow));
				rem -= f, flow += f, e.flow += f, g[e.to][e.rev].flow -= f;
			}
			if(!rem)break;
		}
		if(rem)d[now] = -1;
		return flow;
	}
	
	LL dinic(){
		assert(s!=-1);
		LL flow = 0;
		while(bfs()){
			memset(cur, 0, sizeof cur);
			flow += dfs(s, 1ll << 62);
		}
		return flow;
	}
}nf;

signed main(){
	scanf("%lld%lld",&m,&n);
	s = 0, t = n + m + 1;
	LL ans = 0;
	for(int i=1;i<=m;i++){
		int x;scanf("%lld",&x);
		int tt;
		nf.add(s, i, x);
		while(scanf("%lld",&tt), tt){
			nf.add(i, m+tt, 1ll << 62);
		}
		ans += x;
	}
	nf.init(s, t);
	for(int i=1;i<=n;i++){
		int x;scanf("%lld",&x);
		nf.add(m+i, t, x);
	}
	ans -= nf.dinic();
	printf("%lld\n",max(ans, 0ll));

	return 0;
}

2762

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <cassert>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;
#define int LL

const int inf = 1e18, INF = 0x3f3f3f3f, maxn = 200005;

int n,m,s,t;
struct ed{
	LL from,to,cap,flow,rev;
	ed(){}
	ed(LL from,LL to,LL cap,LL flow,LL rev):from(from),to(to),cap(cap),flow(flow),rev(rev){}
};
vector<ed>g[maxn];
char c[maxn];

struct netflow{
	int cur[maxn]; 
	int d[maxn], q[maxn], hd, tl;
	int s, t;	// 源 汇 
	
	netflow(){s=t=-1;}
	
	void init(int s0,int t0){
		s = s0, t = t0;
	}

	void add(int x,int y,int v){
		g[x].push_back(ed(x,y,v,0,g[y].size()));
		g[y].push_back(ed(y,x,0,0,g[x].size() - 1));
	}
	
	int bfs(){
		memset(d,0, sizeof d);
		hd = tl = 0;
		q[tl ++] = s;
		d[s] = 1;
		while(hd != tl){
			int now = q[hd ++];
			for(int i = 0;i<g[now].size();i++){
				ed &e = g[now][i];
				if(!d[e.to] && e.cap > e.flow)d[e.to] = d[now] + 1, q[tl ++] = e.to;
			}
		}
		return d[t];
	}
	
	LL dfs(int now,LL rem){	// rem 当前流量 
		if(now == t || !rem)return rem;
		LL flow = 0;
		for(int &i = cur[now]; i < g[now].size();i ++){
			ed &e = g[now][i];
				// 分层图 & 残量不为0 
			if(d[e.to] == d[now] + 1 && e.cap > e.flow){
				LL f = dfs(e.to, min(rem, e.cap - e.flow));
				rem -= f, flow += f, e.flow += f, g[e.to][e.rev].flow -= f;
			}
			if(!rem)break;
		}
		if(rem)d[now] = -1;
		return flow;
	}
	
	LL dinic(){
		assert(s!=-1);
		LL flow = 0;
		while(bfs()){
			memset(cur, 0, sizeof cur);
			flow += dfs(s, 1ll << 62);
		}
		return flow;
	}
}nf;

int fg = 0;
int read(){
	fg = 0;
	char ch;int r=0;
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0' && ch <= '9')r = r * 10 + ch -'0', ch = getchar();
	if(ch == '\r')fg = 1;
	return r;
}

signed main(){
//	freopen("Luogu3410.in","r",stdin);
	scanf("%lld%lld",&m,&n);
	s = 0, t = n + m + 1;
	LL ans = 0;
//	for(int i=1;i<=m;i++){
//		int x=read();
//		int tt;
//		nf.add(s, i, x);
//		while(tt=read()){
//			nf.add(i, m+tt, 1ll << 62);
//			if(fg)break;
//		}
//		ans += x;
//	}
	for (int i=1;i<=m;i++){
        int x;scanf("%lld",&x);
        memset(c,0,sizeof(c));
        int ulen, num;
        cin.getline(c,10000);
        ulen=0;		
		nf.add(s, i, x);
        while (sscanf(c+ulen,"%lld",&num)==1){
			nf.add(i, m+num, 1ll << 62);
            if (num==0) ulen++;
            else while (num){num/=10;ulen++;}
            ulen++;
        }
        ans += x;
    }
	nf.init(s, t);
	for(int i=1;i<=n;i++){
		int x;scanf("%lld",&x);
		nf.add(m+i, t, x);
	}
	ans -= nf.dinic();
	for(int i=1;i<=m;i++)if(nf.d[i] > 0)printf("%d ",i);puts("");
	for(int i=1;i<=n;i++)if(nf.d[i+m] > 0)printf("%d ",i);puts("");
	printf("%lld\n",max(ans, 0ll));

	return 0;
}
posted @ 2022-11-23 22:48  SkyRainWind  阅读(15)  评论(0编辑  收藏  举报