BZOJ 2502 上下界网络流

        首先推荐一篇文章http://wenku.baidu.com/link?url=eFIg-AoMXJLIN3iYZzAHmS61E1_eguZurgyYk6HqhZ8fJQLWoR885UIx8q3ADiQiRU62v8KxDhUys4ibYhEn8zID17Otr3hbtQ4GiU8ro6y

        然后就是裸的最小流

        话说网上很多神奇构图都什么心态,二分+Dinic大法好!

#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

const int MAXN = 1001;
const int INF = 10000001;

struct Edge
{
	int from,to,cap,flow;
};

int n,S,T,SS,ST;
int dist[MAXN],a[MAXN],cur[MAXN];
bool vis[MAXN];
vector <Edge> Edges;
vector <int> G[MAXN];

void AddEdge(int from,int to,int cap)
{
	Edges.push_back((Edge){from,to,cap,0});
	Edges.push_back((Edge){to,from,0,0});
	int m = Edges.size();
	G[from].push_back(m-2);
	G[to].push_back(m-1);
}

void clear(int mid)
{
	for (int i=0;i<Edges.size();i++) Edges[i].flow = 0;
	Edges[Edges.size()-2].cap = mid;
}

bool bfs(int s,int t)
{
	memset(dist,0,sizeof(dist));
	queue <int> Q;Q.push(s);
	dist[s] = 1;
	while (!Q.empty())
	{
		int u = Q.front();Q.pop();
		for (int i=0;i<G[u].size();i++)
		{
			Edge e = Edges[G[u][i]];
			if (e.cap <= e.flow) continue;
			if (!dist[e.to])
			{
				dist[e.to] = dist[u]+1;
				Q.push(e.to);
			}
		}
	}
	return dist[t];
}

int dfs(int u,int a,int t)
{
	if (u == t || a <= 0) return a;
	int flow = 0;
	for (int &i = cur[u];i<G[u].size();i++)
	{
		Edge &e = Edges[G[u][i]];
		if (e.cap > e.flow && dist[e.to] == dist[u]+1)
		{
			int f = dfs(e.to,min(a,e.cap-e.flow),t);
			if (f <= 0) continue;
			e.flow += f;
			Edges[G[u][i]^1].flow -= f;
			flow += f;
			a -= f;
			if (a == 0) break;
		}
	}
	return flow;
}

void Dinic(int s,int t)
{
	while (bfs(s,t))
	{
		memset(cur,0,sizeof(cur));
		dfs(s,INF,t);
	}
}

bool check()
{
	for (int i=0;i<G[SS].size();i++) 
	{
		Edge e = Edges[G[SS][i]];
		if (e.cap > e.flow) return false;
	}
	return true;
}

int main()
{
	scanf("%d",&n);
	S = 0, T = n+1;
	SS = n+2, ST = n+3;
	for (int i=1;i<=n;i++)
	{
		int cnt;
		scanf("%d",&cnt);
		for (int j=1;j<=cnt;j++)
		{
			int x;
			scanf("%d",&x);
			AddEdge(i,ST,1);
			AddEdge(SS,x,1);
			AddEdge(i,x,INF);
			vis[x] = true;
		}
		if (cnt == 0) AddEdge(i,T,INF);
	}
	for (int i=1;i<=n;i++) if (!vis[i]) AddEdge(S,i,INF);
	AddEdge(T,S,INF);
	int l = 1, r = 100001;
	while (l+1 != r)
	{
		int mid = (l+r)/2;
		clear(mid);
		Dinic(SS,ST);
		if (check()) r = mid;
		else l = mid;
	}
	printf("%d\n",r);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值