【学习】网络流

听说网络流很好玩。。。其实好久好久好久以前就写过。。。但已经不知道烂到哪个角落里去了QAQ

停课了就先看看网络流呗~~~

感觉网络流最重要的是建图哎。。。不然好像知道是网络流还是流不出来QAQ

不要问为什么所有的画风都是一个样。。。虽然每次都重新手打一遍但是。。。板子用的都是同一个啊

BZOJ-1433&Codevs-2347

才不会说后面的Dinic都是拿这个的。。。

表示做完这题下午考试就有差不多的题好兴奋ヾ(o◕∀◕)ノヾ

源点向所有有床位的连边,需要床位的向汇点连边,如果i可以睡j的床,i向j'连边

//Codevs 2347
#include <iostream> 
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#define S 101
#define INF 0x7fffffff
using namespace std;

int T,n,x;
queue<int> que;
int tot=1,total=0,cnt,a[55],head[110],ne[50010],v[50010],w[50010],h[110],ans=0;
bool BFS()
{
	memset(h,-1,sizeof(h));
	while (!que.empty()) que.pop();
	h[0]=0; que.push(0);
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=ne[i])
		if (w[i]&&h[v[i]]<0)
		{
			h[v[i]]=h[now]+1; que.push(v[i]);
		}
	}
	if (h[S]==-1) return 0; else return 1;
}
int DFS(int xx,int ff)
{
	int tmp,vis=0;
	if (xx==S) return ff;
	for (int i=head[xx];i;i=ne[i])
	{
		if (w[i]&&h[v[i]]==h[xx]+1)
		{
			tmp=ff-vis;
			tmp=DFS(v[i],min(tmp,w[i]));
			w[i]-=tmp;
			w[i^1]+=tmp;
			vis+=tmp;
			if (vis==ff) return ff;
		}
	}
	if (!vis) h[xx]=-1;
	return vis;
}
void Build(int xx,int yy,int zz)
{
	ne[++tot]=head[xx]; head[xx]=tot; v[tot]=yy; w[tot]=zz;
}
int main()
{
	scanf("%d",&T);
	while (T--)
	{
		tot=1,total=ans=0; memset(h,0,sizeof(h));
		memset(head,0,sizeof(head)),memset(v,0,sizeof(v)),memset(w,0,sizeof(w));
		scanf("%d",&n);
		for (int i=1;i<=n;++i) 
		{
			scanf("%d",&a[i]); if (a[i])  Build(i+n,S,1),Build(S,i+n,0);
		}
		for (int i=1;i<=n;++i)
		{
			scanf("%d",&x);
			if ((a[i]&&!x) || !a[i]) Build(0,i,1),Build(i,0,0),total++;
		}
		for (int i=1;i<=n;++i)
			for (int j=1;j<=n;++j)
			{
				scanf("%d",&x);
				if (x || i==j) Build(i,j+n,1),Build(j+n,i,0);
			}
		while(BFS()) ans+=DFS(0,INF);
		if (ans==total) puts("^_^"); else puts("T_T");
	}
	return 0;
}


BZOJ-3996

对,这就是楼上说的那道考试时候做的题~~~

化简结果是这样滴~~

建立S,T; S 连(i,j)边,边权为b[i,j],(i,j)连i,j边,边权为inf,i向T连边,边权为c[i]

答案是sum(b[i][j])-最小割

#include <iostream> 
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
#define INF 0x3f3f3f3f
#define NN 300010
using namespace std;
struct REC
{	int ne,v,w; }e[NN*10];
int x,T,S,k,ans,h[NN],head[NN],tot,n;
queue <int> que;
void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].w=zz;
	e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].w=0;
}
bool BFS()
{
	memset(h,-1,sizeof(h));
	while (!que.empty()) que.pop();
	que.push(0),h[0]=0;
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]<0)
		{	h[e[i].v]=h[now]+1; que.push(e[i].v);
			if (e[i].v==T) return 1; }
	}
	if (h[T]==-1)  return 0; else return 1;
}
int DFS(int xx,int f)
{
	int tmp,vis=f;
	if (xx==T) return f;
	for (int i=head[xx];i;i=e[i].ne)
	if (e[i].w && h[e[i].v]==h[xx]+1)
	{
		tmp=DFS(e[i].v,min(f,e[i].w));
		e[i].w-=tmp,e[i^1].w+=tmp,vis-=tmp;
		if (!vis) return f;
	}
	if (vis==f) h[xx]=-1;
	return f-vis;
}
int main()
{
	scanf("%d",&n); T=n*n+n+1,S=0,k=n,tot=1;
	for (int i=1;i<=n;++i)
		for (int j=1;j<=n;++j)
		{
			scanf("%d",&x); ans+=x;
			Build(S,++k,x);	Build(k,i,INF);	Build(k,j,INF);
		}
	for (int i=1;i<=n;++i) scanf("%d",&x),Build(i,T,x);
	while (BFS()) ans-=DFS(0,INF);
	printf("%d\n",ans);
	return 0;
}

BZOJ-1143&BZOJ-2718

最长反链=最小路径覆盖。。。floyd传递闭包后,用n-二分图最大匹配数即为答案,二分图最大匹配数用网络流你咬我啊~~

2718是权限题。。。本宝宝没有权限号。。只能口胡了

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring> 
#include <queue>
#define INF 0x3f3f3f3f
#define NN 405
#define MM 50005
using namespace std;

int h[NN],head[NN],cur[NN],T,S=0,x,y,a[NN][NN],ans,tot=1,n,m;
struct REC
{
	int ne,v,w;
}e[MM];

void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].w=zz;
	e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].w=0;
}

bool BFS()
{
	queue<int>que;
	memset(h,-1,sizeof(h));
	que.push(0); h[0]=0;
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]==-1)
		{	h[e[i].v]=h[now]+1;	que.push(e[i].v);	}
	}
	if (h[T]==-1) return 0;else return 1;
}

int dfs(int xx,int ff)
{
	if (xx==T) return ff;
	int vis=0;
	for (int i=cur[xx];i;i=e[i].ne)
	if (e[i].w && h[e[i].v]==h[xx]+1)
	{
		int tmp=dfs(e[i].v,min(ff-vis,e[i].w));
		e[i].w-=tmp,e[i^1].w+=tmp;
		if (e[i].w)cur[xx]=i; vis+=tmp;
		if (vis==ff) return vis;
	}
	if (!vis) h[xx]=-1;
	return vis;
}
int main()
{
	scanf("%d%d",&n,&m); T=2*n+1;
	for (int i=1;i<=m;++i) scanf("%d%d",&x,&y),a[x][y]=1;
	for (int k=1;k<=n;++k)
		for (int i=1;i<=n;++i)
			for (int j=1;j<=n;++j)
			if (a[i][k] && a[k][j]) a[i][j]=1;
	for (int i=1;i<=n;++i) Build(0,i,1),Build(i+n,T,1);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=n;++j)
			if (a[i][j]) Build(i,j+n,INF);
	while (BFS()) {	memcpy(cur,head,sizeof(head));	ans+=dfs(0,INF);}
	printf("%d\n",n-ans);
	return 0;
}

BZOJ-2768&BZOJ-1934

这两题一模一样的辣。。。所有赞成的连源点,反对的连汇点,然后是朋友的相互连,跑啊跑就跑粗来惹( ̄︶ ̄)↗

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring> 
#include <queue>
#define INF 0x3f3f3f3f
#define NN 405
#define MM 50005
using namespace std;

int h[NN],head[NN],cur[NN],T,S=0,x,y,a[NN][NN],ans,tot=1,n,m;
struct REC
{
	int ne,v,w;
}e[MM];

void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].w=zz;
	e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].w=0;
}

bool BFS()
{
	queue<int>que;
	memset(h,-1,sizeof(h));
	que.push(0); h[0]=0;
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]==-1)
		{	h[e[i].v]=h[now]+1;	que.push(e[i].v);	}
	}
	if (h[T]==-1) return 0;else return 1;
}

int dfs(int xx,int ff)
{
	if (xx==T) return ff;
	int vis=0;
	for (int i=cur[xx];i;i=e[i].ne)
	if (e[i].w && h[e[i].v]==h[xx]+1)
	{
		int tmp=dfs(e[i].v,min(ff-vis,e[i].w));
		e[i].w-=tmp,e[i^1].w+=tmp;
		if (e[i].w)cur[xx]=i; vis+=tmp;
		if (vis==ff) return vis;
	}
	if (!vis) h[xx]=-1;
	return vis;
}
int main()
{
	scanf("%d%d",&n,&m); T=2*n+1;
	for (int i=1;i<=m;++i) scanf("%d%d",&x,&y),a[x][y]=1;
	for (int k=1;k<=n;++k)
		for (int i=1;i<=n;++i)
			for (int j=1;j<=n;++j)
			if (a[i][k] && a[k][j]) a[i][j]=1;
	for (int i=1;i<=n;++i) Build(0,i,1),Build(i+n,T,1);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=n;++j)
			if (a[i][j]) Build(i,j+n,INF);
	while (BFS()) {	memcpy(cur,head,sizeof(head));	ans+=dfs(0,INF);}
	printf("%d\n",n-ans);
	return 0;
}

BZOJ-3504

如果只能走2次就连一条流量为2的边,如果随便走就连INF的边。起点连源点,终点连汇点。。

不过防止a1走b2的作死就把b1,b2倒一倒再跑一遍,两次都过就可以啦~\(≧▽≦)/~

#include <cstdio> 
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f
#define S 0
#define T 51
using namespace std;

template <int NN,int MM>
struct ISAP
{
	int head[NN],d[NN],gap[NN],cur[NN],pre[NN],tot;
	struct Edge
	{
		int v,ne,w,f;
	}e[MM];
	void cl(){	tot=1; memset(head,0,sizeof(head));	}
	void build(int xx,int yy,int zz)
	{
		e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].w=zz,e[tot].f=0;
		e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].w=0,e[tot].f=0;
	}
	void BFS(int tt)
	{
		queue<int>que;
		que.push(tt);
		memset(d,-1,sizeof(d)); memset(gap,0,sizeof(gap));
		d[tt]=0;
		while (!que.empty())
		{
			int now=que.front(); que.pop();
			++gap[d[now]];
			for (int i=head[now];i;i=e[i].ne)
			if (d[e[i].v]==-1)
			{	d[e[i].v]=d[now]+1;	que.push(e[i].v);}
		}
	}
	int isap(int ss,int tt,int num)
	{
		BFS(tt);
		
		int ans=0,u=ss,flow=INF;
		memcpy(cur,head,sizeof(head));
		while (d[ss]<num)
		{
			int &i=cur[u];
			for (;i;i=e[i].ne)
			if (e[i].w>e[i].f && d[u]==d[e[i].v]+1)
			{
				u=e[i].v;
				pre[e[i].v]=i;
				flow=min(flow,e[i].w-e[i].f);
				if (u==tt)
				{
					while(u!=ss)
					{
						e[pre[u]].f+=flow;
						e[pre[u]^1].f-=flow;
						u=e[pre[u]^1].v;
					}
					ans+=flow; flow=INF;
				}
				break;
			}
			if (i==0)
			{
				if (--gap[d[u]]==0) break;
				int dmin=num-1;
				cur[u]=head[u];
				for (int j=head[u];j;j=e[j].ne)
				if (e[j].w>e[j].f) dmin=min(dmin,d[e[j].v]);
				d[u]=dmin+1,++gap[d[u]];
				if (u!=ss) u=e[pre[u]^1].v;
			}
		}
		return ans;
	}
};
ISAP<1000,1000000> Sap;

int n,a1,a2,an,b1,b2,bn,a[55][55];

int main()
{
	while (scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF)
	{
		a1++,a2++,b1++,b2++;
		memset(a,0,sizeof(a));
		for (int i=1;i<=n;++i)
		{
			char ch[55];
			scanf("%s",ch);
			for (int j=1;j<=n;++j)
				if (ch[j-1]=='O') a[i][j]=1;
				else if (ch[j-1]=='N') a[i][j]=2;
		}
		//for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) printf("%d ",a[i][j]);
		Sap.cl();
		for (int i=1;i<=n;++i)
			for (int j=1;j<=n;++j)
				if (a[i][j]==1) Sap.build(i,j,2);
				else if (a[i][j]==2) Sap.build(i,j,INF);
		Sap.build(S,a1,an*2); Sap.build(S,b1,bn*2);
		Sap.build(a2,T,an*2); Sap.build(b2,T,bn*2);
		if (Sap.isap(S,T,Sap.tot)<(an+bn)*2)	{	puts("No"); continue;}
		
		Sap.cl();
		for (int i=1;i<=n;++i)
			for (int j=1;j<=n;++j)
				if (a[i][j]==1) Sap.build(i,j,2);
				else if (a[i][j]==2) Sap.build(i,j,INF);
		Sap.build(S,a1,an*2); Sap.build(S,b2,bn*2);
		Sap.build(a2,T,an*2); Sap.build(b1,T,bn*2);
		if (Sap.isap(S,T,Sap.tot)<(an+bn)*2) { puts("No"); continue;}
		puts("Yes");
	}
	return 0;
}

BZOJ-1001

QAQ我才不会说窝连bzoj1000都没做呢╮(╯_╰)╭

感觉题目写得好明显的了呢~~
不过源点是1,汇点是n*m,憋搞错就可以咯

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f
#define NN 1000010
using namespace std;

int tot=1,n,m,S=1,T,x,head[NN],h[NN],ans=0;
struct REC
{
	int ne,v,w;
}e[NN<<3];

void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].w=zz;
	e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].w=zz;
}

bool BFS()
{
	queue<int> que; memset(h,-1,sizeof(h));
	que.push(S); h[S]=0;
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]<0)
		{
			h[e[i].v]=h[now]+1; que.push(e[i].v);
		}
	}
	return h[T]!=-1;
}

int DFS(int xx,int ff)
{
	if (xx==T) return ff;
	int vis=0;
	for (int i=head[xx];i;i=e[i].ne)
	if (h[e[i].v]==h[xx]+1 && e[i].w)
	{
		int tmp=DFS(e[i].v,min(ff-vis,e[i].w));
		e[i].w-=tmp, e[i^1].w+=tmp, vis+=tmp;
		if (vis==ff) return ff;
	}
	if (!vis) h[xx]=-1;
	return vis;
}

int main()
{
	scanf("%d%d",&n,&m); T=n*m;
	for (int i=1;i<=n;++i)
		for (int j=1;j<m;++j)
			scanf("%d",&x),Build((i-1)*m+j,(i-1)*m+j+1,x);
	for (int i=1;i<n;++i)
		for (int j=1;j<=m;++j)
			scanf("%d",&x),Build((i-1)*m+j,i*m+j,x);
	for (int i=1;i<n;++i)
		for (int j=1;j<m;++j)
			scanf("%d",&x),Build((i-1)*m+j,i*m+j+1,x);
	while (BFS()) ans+=DFS(1,INF);
	printf("%d\n",ans);
	return 0;
}

BZOJ-1497

这里讲得挺清楚了呢:传送门http://www.cnblogs.com/NanoApe/p/4442624.html

#include <iostream> 
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f
#define NN 100100
#define MM 1000010
using namespace std;

int head[NN],h[NN],x,y,z,n,m,ans=0,tot=1,S=0,T;
struct REC
{
	int ne,v,w;
}e[MM];

void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].w=zz;
	e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].w=0;
}

bool BFS()
{
	queue<int>que; memset(h,-1,sizeof(h));
	que.push(S), h[S]=0;
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
			if (e[i].w && h[e[i].v]<0)
				que.push(e[i].v), h[e[i].v]=h[now]+1;
	}
	return h[T]!=-1;
}

int DFS(int xx,int ff)
{
	if (xx==T) return ff;
	int vis=0;
	for (int i=head[xx];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]==h[xx]+1)
		{
			int tmp=DFS(e[i].v,min(ff-vis,e[i].w));
			e[i].w-=tmp, e[i^1].w+=tmp, vis+=tmp;
			if (vis==ff) return ff;
		}
	if (!vis) h[xx]=-1;
	return vis;
}

int main()
{
	scanf("%d%d",&n,&m); T=n+m+1;
	memset(head,0,sizeof(head));
	for (int i=1;i<=n;++i) scanf("%d",&x),Build(i,T,x);
	for (int i=1;i<=m;++i) 
		scanf("%d%d%d",&x,&y,&z),Build(i+n,x,INF),Build(i+n,y,INF),Build(S,i+n,z),ans+=z;
	while (BFS()) ans-=DFS(S,INF);
	printf("%d\n",ans);
	return 0;
}

BZOJ-1412

源点向所有羊连无穷边,羊向狼连流量为1的边,所有狼向汇点连无穷边跑最大流
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
#define INF 0x3f3f3f3f
#define MM 500010
#define NN 10010

int head[NN],h[NN],tot=1,n,m,a[110][110],S=0,T=10001,ans=0;
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};

struct REC
{
	int v,w,ne;
}e[MM];

void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].w=zz;
	e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].w=0;
}

bool BFS()
{
	queue<int> que; memset(h,-1,sizeof(h));
	que.push(S); h[S]=0;
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]<0)
			h[e[i].v]=h[now]+1, que.push(e[i].v);
	}
	return h[T]!=-1;
}

int DFS(int xx,int ff)
{
	if (xx==T) return ff;
	int vis=0;
	for (int i=head[xx];i;i=e[i].ne)
	if (h[e[i].v]==h[xx]+1 && e[i].w)
	{
		int tmp=DFS(e[i].v,min(ff-vis,e[i].w));
		e[i].w-=tmp, e[i^1].w+=tmp, vis+=tmp;
		if (vis==ff) return ff;
	}
	if (!vis) h[xx]=-1;
	return vis;
}


int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j) scanf("%d",&a[i][j]);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
		{
			if (a[i][j]==1) Build(0,(i-1)*m+j,INF);
			else if (a[i][j]==2) Build((i-1)*m+j,T,INF);
			for (int k=0;k<4;++k)
			{
				int xx=i+dx[k],yy=j+dy[k];
				if (xx<1 || yy<1 || xx>n || yy>m || a[i][j]==2) continue;
				if (a[i][j]!=1 || a[xx][yy]!=1)
					Build((i-1)*m+j,(xx-1)*m+yy,1);
			}
		}
	while (BFS()) ans+=DFS(S,INF);
	printf("%d\n",ans);
	return 0;
}

BZOJ-1066

源点向每只蜥蜴连1的边,蜥蜴向每个能到的石柱连边,如果蜥蜴能到边界,向汇点连无穷边跑最大流

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f
#define NN 1010
#define MM 500010
#define N 25
using namespace std;

int tot=1,ans=0,S=0,T=801,head[NN],h[NN],a[N][N],mark[N][N],n,m,d;
char ch[N];
struct REC
{
	int ne,v,w;
}e[MM];

void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].w=zz;
	e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].w=0;
}

bool BFS()
{
	queue<int> que; memset(h,-1,sizeof(h));
	que.push(S); h[S]=0;
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]<0)
		{
			h[e[i].v]=h[now]+1; que.push(e[i].v);
		}
	}
	return h[T]!=-1;
}

int DFS(int xx,int ff)
{
	if (xx==T) return ff;
	int vis=0;
	for (int i=head[xx];i;i=e[i].ne)
	if (h[e[i].v]==h[xx]+1 && e[i].w)
	{
		int tmp=DFS(e[i].v,min(ff-vis,e[i].w));
		e[i].w-=tmp, e[i^1].w+=tmp, vis+=tmp;
		if (vis==ff) return ff;
	}
	if (!vis) h[xx]=-1;
	return vis;
}

bool Judge(int xa,int ya,int xb,int yb)
{
	if (((xa-xb)*(xa-xb)+(ya-yb)*(ya-yb))<=(d*d) && a[xa][ya] && a[xb][yb]) return 1;
	else return 0;
}

int main()
{
	scanf("%d%d%d",&n,&m,&d);
	for (int i=1;i<=n;++i)
	{
		scanf("%s",ch+1);
		for (int j=1;j<=m;++j) a[i][j]=ch[j]-'0';
	}
	int tmp=0;
	for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) mark[i][j]=++tmp;
	for (int i=1;i<=n;++i)
	{
		scanf("%s",ch+1);
		for (int j=1;j<=m;++j)
			if (ch[j]=='L') Build(S,mark[i][j],1),++ans;
	}
	for (int i=1;i<=d;++i)
		for (int j=d+1;j<=n-d;++j)
			Build(mark[j][i]+400,T,INF),Build(mark[j][m-i+1]+400,T,INF);
	for (int i=1;i<=d;++i)
		for (int j=1;j<=m;++j)
			Build(mark[i][j]+400,T,INF),Build(mark[n-i+1][j]+400,T,INF);
	for (int xa=1;xa<=n;xa++)
		for (int ya=1;ya<=m;ya++)
			for (int xb=xa-d;xb<=xa+d;xb++)
				for (int yb=ya-d;yb<=ya+d;yb++)
					if (Judge(xa,ya,xb,yb) && (xa!=xb || ya!=yb))
						Build(mark[xa][ya]+400,mark[xb][yb],INF);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
			if (a[i][j]) Build(mark[i][j],mark[i][j]+400,a[i][j]);
	while (BFS()) ans-=DFS(S,INF);
	printf("%d\n",ans);
	return 0;
}

BZOJ-3158

发现两两关系只会发生在奇数特征值和偶数特征值的点之间,源点向所有偶数特征值的点连流量为价值的边,所有奇数特征值的点向汇点连流量为价值的边,所有偶数特征值的点向有冲突的奇数特征值的点连流量无穷的边,就变成最小割模型,答案为所有收益-流量

听说3275也是一样哦。。然而苯宝宝没有权限号哦

所以就这样口胡辣

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f
#define NN 1005
#define MM 1000005
#define LL long long
using namespace std;
 
queue <int> que;
struct REC
{
    int ne,v,w;
}e[MM];
int tot=1,n,a[NN],b[NN],head[NN],h[NN],S=0,T,ans;
void Build(int xx,int yy,int zz)
{
    e[++tot].ne=head[xx], head[xx]=tot, e[tot].v=yy, e[tot].w=zz;
    e[++tot].ne=head[yy], head[yy]=tot, e[tot].v=xx, e[tot].w=0;
}
bool BFS()
{
    while (!que.empty()) que.pop();
    memset(h,-1,sizeof(h));
    que.push(S), h[S]=0;
    while (!que.empty())
    {
        int now=que.front(); que.pop();
        for (int i=head[now];i;i=e[i].ne)
            if (e[i].w && h[e[i].v]<0)
                h[e[i].v]=h[now]+1, que.push(e[i].v);
    }
    if (h[T]==-1) return 0; else return 1;
}
int DFS(int xx,int ff)
{
    if (xx==T) return ff;
    int vis=0;
    for (int i=head[xx];i;i=e[i].ne)
        if (e[i].w && h[e[i].v]==h[xx]+1)
        {
            int tmp=DFS(e[i].v,min(ff-vis,e[i].w));
            e[i].w-=tmp, e[i^1].w+=tmp, vis+=tmp;
            if (vis==ff) return vis;
        }
    if (!vis) h[xx]=-1;
    return vis;
}
int GCD(int a,int b)
{
    while (a)a ^= b ^= a ^= b %= a;
    return b;
}
bool Judge(int xx,int yy)
{
    LL tmp=(LL)xx*xx+(LL)yy*yy,sq=sqrt(tmp);
    if (sq*sq!=tmp) return 1;
    if (GCD(xx,yy)>1) return 1;
    return 0;
}
int main()
{
    scanf("%d",&n); T=n+1;
    for (int i=1;i<=n;++i) scanf("%d",&a[i]);
    for (int i=1;i<=n;++i) scanf("%d",&b[i]),ans+=b[i];
    for (int i=1;i<=n;++i)
        if (a[i]%2==1) Build(S,i,b[i]); else Build(i,T,b[i]);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            if ((a[i]%2==1) && (a[j]%2==0))
                if (!Judge(a[i],a[j])) Build(i,j,INF);
    while (BFS()) ans-=DFS(S,INF);
    printf("%d\n",ans);
    return 0;
}

BZOJ-1305

二分答案ans,每个男孩拆成两个点ai和ai',每个女孩拆成两个点bi和bi',源点向每个ai连一条流量为ans的边,每个bi向汇点连一条流量为ans的边,如果男孩i喜欢女孩j,ai向bi连一条流量为1的边,否则ai'向bi'连一条流量为1的边,每个ai向ai'连一条流量为k的边,表示最多和k个不喜欢的女孩跳舞;每个bi'向bi连一条流量为k的边,如果流量=ans*n则可行,l=mid+1,否则r=mid

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f
#define NN 1005
#define MM 1000005
#define LL long long
using namespace std;
 
queue <int> que;
struct REC
{
    int ne,v,w;
}e[MM];
int tot=1,n,a[NN],b[NN],head[NN],h[NN],S=0,T,ans;
void Build(int xx,int yy,int zz)
{
    e[++tot].ne=head[xx], head[xx]=tot, e[tot].v=yy, e[tot].w=zz;
    e[++tot].ne=head[yy], head[yy]=tot, e[tot].v=xx, e[tot].w=0;
}
bool BFS()
{
    while (!que.empty()) que.pop();
    memset(h,-1,sizeof(h));
    que.push(S), h[S]=0;
    while (!que.empty())
    {
        int now=que.front(); que.pop();
        for (int i=head[now];i;i=e[i].ne)
            if (e[i].w && h[e[i].v]<0)
                h[e[i].v]=h[now]+1, que.push(e[i].v);
    }
    if (h[T]==-1) return 0; else return 1;
}
int DFS(int xx,int ff)
{
    if (xx==T) return ff;
    int vis=0;
    for (int i=head[xx];i;i=e[i].ne)
        if (e[i].w && h[e[i].v]==h[xx]+1)
        {
            int tmp=DFS(e[i].v,min(ff-vis,e[i].w));
            e[i].w-=tmp, e[i^1].w+=tmp, vis+=tmp;
            if (vis==ff) return vis;
        }
    if (!vis) h[xx]=-1;
    return vis;
}
int GCD(int a,int b)
{
    while (a)a ^= b ^= a ^= b %= a;
    return b;
}
bool Judge(int xx,int yy)
{
    LL tmp=(LL)xx*xx+(LL)yy*yy,sq=sqrt(tmp);
    if (sq*sq!=tmp) return 1;
    if (GCD(xx,yy)>1) return 1;
    return 0;
}
int main()
{
    scanf("%d",&n); T=n+1;
    for (int i=1;i<=n;++i) scanf("%d",&a[i]);
    for (int i=1;i<=n;++i) scanf("%d",&b[i]),ans+=b[i];
    for (int i=1;i<=n;++i)
        if (a[i]%2==1) Build(S,i,b[i]); else Build(i,T,b[i]);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            if ((a[i]%2==1) && (a[j]%2==0))
                if (!Judge(a[i],a[j])) Build(i,j,INF);
    while (BFS()) ans-=DFS(S,INF);
    printf("%d\n",ans);
    return 0;
}

BZOJ-2039

源点向每个员工连流量为收益的边,每两个员工之间连Ei,j*2的边,每个员工i再向汇点连ΣEi,j的边,得到最小割模型,答案即为sum-流量

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstring>
#define INF 0x3f3f3f3f
#define LL long long
#define NN 1010
#define MM 2001000
using namespace std;
 
queue<int>que;
int n,m,S,T,head[NN],h[NN],tot=1;
LL summ,sum[NN],mp[NN][NN],a[NN];
struct Edge
{
    int v,ne; LL w;
}e[MM];
void Build(int xx,int yy,LL zz) {e[++tot].ne=head[xx], head[xx]=tot, e[tot].v=yy, e[tot].w=zz;}
bool BFS()
{
    while (!que.empty()) que.pop();
    memset(h,-1,sizeof(h)); h[S]=0, que.push(S);
    while (!que.empty())
    {
        int now=que.front(); que.pop();
        for (int i=head[now];i;i=e[i].ne)
            if (e[i].w && h[e[i].v]<0)
                h[e[i].v]=h[now]+1, que.push(e[i].v);
    }
    return h[T]!=-1;
}
 
LL DFS(int xx,LL ff)
{
    if (xx==T) return ff;
    LL vis=0ll;
    for (int i=head[xx];i;i=e[i].ne)
        if (e[i].w && h[e[i].v]==h[xx]+1)
        {
            LL tmp=DFS(e[i].v,min(e[i].w,ff-vis));
            e[i].w-=tmp, e[i^1].w+=tmp, vis+=tmp;
            if (vis==ff) return vis;
        }
    if (!vis) h[xx]=-1;
    return vis;
}
 
int main()
{
    scanf("%d",&n); S=n+1, T=n+2;
    for (int i=1;i<=n;++i) scanf("%lld",&a[i]);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j) scanf("%lld",&mp[i][j]),sum[i]+=mp[i][j];
    for (int i=1;i<=n;++i) Build(S,i,sum[i]), Build(i,S,0), summ+=sum[i];
    for (int i=1;i<=n;++i) Build(i,T,a[i]), Build(T,i,0);
    for (int i=1;i<=n;++i)
        for (int j=i+1;j<=n;++j) Build(i,j,mp[i][j]*2), Build(j,i,mp[i][j]*2);
    while (BFS()) summ-=DFS(S,INF);
    printf("%lld\n",summ);
    return 0;
}

BZOJ-1221

自己生日的题号哎。。。

开始做费用流咯。。。尽快把板子记下来哦

拆点,源点向每个i连一条流量无穷费用f的边表示直接买毛巾,每个i向i'连一条流量无穷费用0的边,每个i'向t连一条流量为ni费用0的边,表示需要的毛巾;每个i'向i+a连一条流量无穷费用fa的边,表示快洗;每个i'向i+b连一条流量无穷费用fb的边,表示慢洗

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
#define INF 0x3f3f3f3f
#define NN 2100
#define MM 200000
using namespace std;

int n,a,b,f,faa,fbb,dis[NN],fa[NN],tot=1,head[NN],x,S=0,T,ans;
queue<int>que;
bool vis[NN];
struct REC
{
	int ne,v,u,c,w;
}e[MM];

void Build(int xx,int yy,int zz,int cc)
{
	e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].u=xx,e[tot].w=zz,e[tot].c=cc;
	e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].u=yy,e[tot].w=0,e[tot].c=-cc;
}
bool SPFA()
{
	memset(dis,0x3f,sizeof(dis));
	while (!que.empty()) que.pop();
	que.push(S), dis[S]=0;
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && dis[e[i].v]>dis[now]+e[i].c)
		{
			dis[e[i].v]=dis[now]+e[i].c;
			fa[e[i].v]=i;
			if (!vis[e[i].v])
			{
				vis[e[i].v]=1; que.push(e[i].v);
			}
		}
		vis[now]=0;
	}
	if (dis[T]==INF) return 0; else return 1;
}

void MCF()
{
	int xx=INF;
	for (int i=fa[T];i;i=fa[e[i].u]) xx=min(e[i].w,xx);
	for (int i=fa[T];i;i=fa[e[i].u]) e[i].w-=xx, e[i^1].w+=xx, ans+=xx*e[i].c;
}

int main()
{
	scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&faa,&fbb); T=n*2+1;
	for (int i=1;i<=n;++i) 
	{
		scanf("%d",&x), Build(S,i+n,INF,f), Build(S,i,x,0), Build(i+n,T,x,0);
		if (i<n) Build(i,i+1,INF,0);
		if (i+a+1<=n) Build(i,i+n+a+1,INF,faa);
		if (i+b+1<=n) Build(i,i+n+b+1,INF,fbb);
	}
	while (SPFA()) MCF();
	printf("%d\n",ans);
	return 0;
}

BZOJ-2424

当然也是一道费用流的题啊QAQ

拆点,源点向i连一条流量无穷,费用di的边,表示订货,i向i'连一条流量无穷费用为0的边,所有i'向汇点连流量ui费用0的边表示卖出,所有i向i+1连一条流量S费用m的边表示存储费用,然后跑费用流

#include <iostream> 
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstdlib>
#define INF 0x3f3f3f3f
#define NN 2005
#define MM 1000010
#define LL long long
using namespace std;
queue<int>que;
 
int tot=1,dis[NN],head[NN],fa[NN],n,m,s,x,S=0,T=2001;
LL ans;
bool vis[NN];
struct Edge
{
    int ne,u,v,w,c;
}e[MM];
void Build(int xx,int yy,int zz,int cc)
{
    e[++tot].ne=head[xx], head[xx]=tot, e[tot].v=yy, e[tot].u=xx, e[tot].w=zz, e[tot].c=cc;
    e[++tot].ne=head[yy], head[yy]=tot, e[tot].v=xx, e[tot].u=yy, e[tot].w=0, e[tot].c=-cc;
}
bool SPFA()
{
    memset(dis,0x3f,sizeof(dis));
    while (!que.empty()) que.pop();
    que.push(S), dis[S]=0; vis[S]=1;
    while (!que.empty())
    {
        int now=que.front(); que.pop();
        for (int i=head[now];i;i=e[i].ne)
        if (e[i].w && dis[e[i].v]>dis[now]+e[i].c)
        {
            dis[e[i].v]=dis[now]+e[i].c;
            fa[e[i].v]=i;
            if (!vis[e[i].v]) vis[e[i].v]=1, que.push(e[i].v);
        }
        vis[now]=0;
    }
    if (dis[T]==INF) return 0; else return 1;
}
 
void MCF()
{
    int xx=INF;
    for (int i=fa[T];i;i=fa[e[i].u]) xx=min(xx,e[i].w);
    for (int i=fa[T];i;i=fa[e[i].u]) e[i].w-=xx, e[i^1].w+=xx, ans+=(LL)xx*e[i].c;
}
 
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for (int i=1;i<=n;++i) scanf("%d",&x), Build(i,T,x,0);
    for (int i=1;i<=n;++i) scanf("%d",&x), Build(S,i,INF,x);
    for (int i=1;i<=n;++i) Build(i,i+1,s,m);
    while (SPFA()) MCF();
    printf("%lld",ans);
    return 0;
}

BZOJ-2245

源点向每类产品连流量为Ci的边,每类产品向能生产该产品的员工连无穷边,每个员工在每一段上向汇点连t[i]-t[i-1]流量w[i]费用的边,跑费用流即可

#include <iostream> 
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstdlib>
#define INF 0x3f3f3f3f
#define LL long long
#define NN 255
#define MM 500010
#define SS 11
#define N 1005
using namespace std;
queue<int>que;
int dis[N],head[N],c[NN],s[NN],t[NN][SS],w[NN][SS],fa[N],a[NN][NN],n,m,T=1001,S=0,tot=1;
LL ans=0;
bool vis[N];
struct Edge
{
    int ne,u,v,w,c;
}e[MM];
void Build(int xx,int yy,int zz,int cc)
{
    e[++tot].ne=head[xx], head[xx]=tot, e[tot].v=yy, e[tot].u=xx, e[tot].w=zz, e[tot].c=cc;
    e[++tot].ne=head[yy], head[yy]=tot, e[tot].v=xx, e[tot].u=yy, e[tot].w=0, e[tot].c=-cc;
}
bool SPFA()
{
    memset(dis,0x3f,sizeof(dis));
    while (!que.empty()) que.pop();
    dis[S]=0, vis[S]=1, que.push(S);
    while (!que.empty())
    {
        int now=que.front(); que.pop();
        for (int i=head[now];i;i=e[i].ne)
        if (e[i].w && dis[e[i].v]>dis[now]+e[i].c)
        {
            dis[e[i].v]=dis[now]+e[i].c;
            fa[e[i].v]=i;
            if (!vis[e[i].v]) vis[e[i].v]=1, que.push(e[i].v);
        }
        vis[now]=0;
    }
    if (dis[T]==INF) return 0; else return 1;
}
 
void MCF()
{
    int xx=INF;
    for (int i=fa[T];i;i=fa[e[i].u]) xx=min(xx,e[i].w);
    for (int i=fa[T];i;i=fa[e[i].u]) e[i].w-=xx, e[i^1].w+=xx, ans+=(LL)e[i].c*xx;
}
 
int main()
{
    scanf("%d%d",&m,&n);
    for (int i=1;i<=n;++i) scanf("%d",&c[i]);
    for (int i=1;i<=m;++i)
        for (int j=1;j<=n;++j) scanf("%d",&a[i][j]);
    for (int i=1;i<=m;++i)
    {
        scanf("%d",&s[i]);
        for (int j=1;j<=s[i];++j) scanf("%d",&t[i][j]);
        t[i][s[i]+1]=INF;
        for (int j=1;j<=s[i]+1;++j) scanf("%d",&w[i][j]);
    }
    for (int i=1;i<=n;++i) Build(S,i,c[i],0);
    for (int i=1;i<=m;++i)
        for (int j=1;j<=n;++j)
            if (a[i][j]) Build(j,i+n,INF,0);
    for (int i=1;i<=m;++i)
        for (int j=1;j<=s[i]+1;++j) Build(i+n,T,t[i][j]-t[i][j-1],w[i][j]);
    while (SPFA()) MCF();
    printf("%lld",ans);
    return 0;
}

听说有网络流24题。。。

太空飞行计划问题

#include <iostream> 
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#define NN 301
#define MM 200010
#define INF 0x7fffffff
using namespace std;

struct REC
{
	int ne,w,v;
}e[MM];
int m,n,ans,sum,x,head[NN],tot=1,h[NN],T,S=0;

void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx]; head[xx]=tot; e[tot].v=yy; e[tot].w=zz;
	e[++tot].ne=head[yy]; head[yy]=tot; e[tot].v=xx; e[tot].w=0;
}

bool BFS()
{
	queue <int> que;
	memset(h,-1,sizeof(h)); h[0]=0;
	que.push(0);
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]<0)
		{
			h[e[i].v]=h[now]+1;
			que.push(e[i].v);
		}
	}
	if (h[T]==-1) return 0; else return 1;
}

int DFS(int xx,int ff)
{
	int vis=0;
	if (xx==T) return ff;
	for (int i=head[xx];i;i=e[i].ne)
	if (e[i].w && h[e[i].v]==h[xx]+1)
	{
		int tmp=ff-vis;
		tmp=DFS(e[i].v,min(tmp,e[i].w));
		e[i].w-=tmp;
		e[i^1].w+=tmp;
		vis+=tmp;
		if (vis==ff) return ff;
	}
	if (!vis) h[xx]=-1;
	return vis;
}

int main()
{
	scanf("%d%d",&m,&n); T=n+m+1;
	for (int i=1;i<=m;++i)
	{
		scanf("%d",&x),sum+=x;
		Build(S,i,x);
		while (getchar()!='\n')
		{
			scanf("%d",&x);
			Build(i,x+m,INF);
		}
	}
	for (int i=1;i<=n;++i)
		scanf("%d",&x),Build(i+m,T,x);
	while (BFS()) ans+=DFS(0,INF);
	printf("%d\n",sum-ans);
	return 0;
}

最小路径覆盖问题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#define INF 0x7fffffff
#define NN 210
#define MM 400010
using namespace std;

struct REC
{
	int v,ne,w;
}e[MM];
int head[NN<<2],n,m,x,y,S,T,h[NN<<2],tot=1,ans;
void Build(int xx,int yy,int zz)
{
	e[++tot].v=yy; e[tot].ne=head[xx]; head[xx]=tot; e[tot].w=zz;
	e[++tot].v=xx; e[tot].ne=head[yy]; head[yy]=tot; e[tot].w=0;
}

bool BFS()
{
	memset(h,-1,sizeof(h)); h[0]=0;
	queue <int> que;
	que.push(0);
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w && h[e[i].v]<0)
		{
			h[e[i].v]=h[now]+1;
			que.push(e[i].v);
		}
	}
	if (h[T]==-1) return 0; else return 1;
}

int DFS(int xx,int ff)
{
	if (xx==T) return ff;
	int vis=0;
	for (int i=head[xx];i;i=e[i].ne)
	if (e[i].w && h[e[i].v]==h[xx]+1)
	{
		int tmp=ff-vis;
		tmp=DFS(e[i].v,min(e[i].w,tmp));
		e[i].w-=tmp;
		e[i^1].w+=tmp;
		vis+=tmp;
		if (vis==ff) return ff;
	}
	if (!vis) h[xx]=-1;
	return vis;
}

int main()
{
	scanf("%d%d",&n,&m);
	S=0,T=n*2+1;
	for (int i=1;i<=m;++i)
	{
		scanf("%d%d",&x,&y);
		Build(x,y+n,INF);
	}
	for (int i=1;i<=n;++i) Build(S,i,1),Build(i+n,T,1);
	ans=n;
	while (BFS()) ans-=DFS(0,INF);
	printf("%d\n",ans);
	return 0;
}

魔术球问题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#define NN 10010
#define MM 200010
#define INF 0x7fffffff
using namespace std;

int n,m=0,ans=0,head[NN],h[NN],tot=1,S=0,T=NN-10;
struct REC
{
	int ne,v,w;
}e[MM];

bool BFS()
{
	queue<int> que;
	memset(h,-1,sizeof(h)); h[0]=0;
	que.push(0);
	while (!que.empty())
	{
		int now=que.front(); que.pop();
		for (int i=head[now];i;i=e[i].ne)
		if (e[i].w&&h[e[i].v]<0)
		{
			h[e[i].v]=h[now]+1;
			que.push(e[i].v);
		}
	}
	if (h[T]==-1) return 0;else return 1;
}

int DFS(int xx,int ff)
{
	if (xx==T) return ff;
	int vis=0;
	for (int i=head[xx];i;i=e[i].ne)
	if (e[i].w && h[e[i].v]==h[xx]+1)
	{
		int tmp=ff-vis;
		tmp=DFS(e[i].v,min(e[i].w,tmp));
		e[i].w-=tmp;
		e[i^1].w+=tmp;
		vis+=tmp;
		if (vis==ff) return ff;
	}
	if (!vis) h[xx]=-1;
	return vis;
}

void Build(int xx,int yy,int zz)
{
	e[++tot].ne=head[xx]; head[xx]=tot; e[tot].v=yy; e[tot].w=zz;
	e[++tot].ne=head[yy]; head[yy]=tot; e[tot].v=xx; e[tot].w=0;
}

int main()
{
	scanf("%d",&n);
	while (1)
	{
		m++,ans++;
		for (int i=1;i<m;++i)
		if (sqrt(i+m)==(int)sqrt(i+m)) Build(i,m+5000,1);
		Build(S,m,1); Build(m+5000,T,1);
		while (BFS()) ans-=DFS(0,INF);
		if (ans>n)
		{
			printf("%d\n",m-1); return 0;
		}
	}
	return 0;
}

圆桌问题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
int x,n,m,S,T;
template <int NN,int MM>
struct ISAP
{
	int head[NN],d[NN],gap[NN],cur[NN],pre[NN],tot;
	struct Edge
	{
		int ne,v,w,f;
	}e[MM];
        void cl()
	{
		tot=1; memset(e,0,sizeof(e)); memset(head,0,sizeof(head));
	}
	void build(int xx,int yy,int zz)
	{
		e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].f=0,e[tot].w=zz;
		e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].f=0,e[tot].w=0;
	}
	void bfs(int tt)
	{
		queue<int>que;
		que.push(tt);
		memset(d,-1,sizeof(d));
		memset(gap,0,sizeof(gap));
		d[tt]=0;
		while (!que.empty())
		{
			int now=que.front(); que.pop();
			++gap[d[now]];
			for (int i=head[now];i;i=e[i].ne)
			if (d[e[i].v]==-1)
			{
				d[e[i].v]=d[now]+1;
				que.push(e[i].v);
			}
		}
	}
	int isap(int ss,int tt,int num)
	{
		bfs(tt);
		int ans=0,u=ss,flow=INF;
		memcpy(cur,head,sizeof(head));
		while (d[ss]<num)
		{
			int &i=cur[u];
			for (;i;i=e[i].ne)
			if (e[i].w>e[i].f && d[u]==d[e[i].v]+1)
			{
				u=e[i].v;
				pre[e[i].v]=i;
				flow=min(flow,e[i].w-e[i].f);
				if (u==tt)
				{
					while (u!=ss)
					{
						e[pre[u]].f+=flow;
						e[pre[u]^1].f-=flow;
						u=e[pre[u]^1].v;
					}
					ans+=flow; flow=INF;
				}
				break;
			}
			if (i==0)
			{
				if (--gap[d[u]]==0) break;
				int minn=num-1;
				cur[u]=head[u];
				for (int j=head[u];j;j=e[j].ne)
					if (e[j].w>e[j].f) minn=min(minn,d[e[j].v]);
				d[u]=minn+1; ++gap[d[u]];
				if (u!=ss) u=e[pre[u]^1].v;
			}
		}
		return ans;
	}
};
ISAP<1000, 1000000> Sap;

int main()
{
	scanf("%d%d",&m,&n); S=0,T=n+m+1; Sap.cl();
	for (int i=1;i<=m;++i) scanf("%d",&x),Sap.build(S,i,x);
	for (int i=1;i<=n;++i) scanf("%d",&x),Sap.build(i+m,T,x);
	for (int i=1;i<=m;++i)
		for (int j=1;j<=n;++j) Sap.build(i,j+m,1);
	printf("%d\n",Sap.isap(S,T,Sap.tot));
	return 0;
}

最长递增子序列问题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;

template <int NN,int MM>
struct ISAP
{
	int head[NN],d[NN],gap[NN],cur[NN],pre[NN],tot=1;
	struct Edge
	{
		int ne,v,w,f;
	}e[MM];
	void cl()
	{
		tot=1; memset(e,0,sizeof(e)); memset(head,0,sizeof(head));
	}
	void build(int xx,int yy,int zz)
	{
		e[++tot].ne=head[xx],head[xx]=tot,e[tot].v=yy,e[tot].f=0,e[tot].w=zz;
		e[++tot].ne=head[yy],head[yy]=tot,e[tot].v=xx,e[tot].f=0,e[tot].w=0;
	}
	void bfs(int tt)
	{
		queue<int>que;
		que.push(tt);
		memset(d,-1,sizeof(d));
		memset(gap,0,sizeof(gap));
		d[tt]=0;
		while (!que.empty())
		{
			int now=que.front(); que.pop();
			++gap[d[now]];
			for (int i=head[now];i;i=e[i].ne)
			if (d[e[i].v]==-1)
			{
				d[e[i].v]=d[now]+1;
				que.push(e[i].v);
			}
		}
	}
	int isap(int ss,int tt,int num)
	{
		bfs(tt);
		int ans=0,u=ss,flow=INF;
		memcpy(cur,head,sizeof(head));
		while (d[ss]<num)
		{
			int &i=cur[u];
			for (;i;i=e[i].ne)
			if (e[i].w>e[i].f && d[u]==d[e[i].v]+1)
			{
				u=e[i].v;
				pre[e[i].v]=i;
				flow=min(flow,e[i].w-e[i].f);
				if (u==tt)
				{
					while (u!=ss)
					{
						e[pre[u]].f+=flow;
						e[pre[u]^1].f-=flow;
						u=e[pre[u]^1].v;
					}
					ans+=flow; flow=INF;
				}
				break;
			}
			if (i==0)
			{
				if (--gap[d[u]]==0) break;
				int minn=num-1;
				cur[u]=head[u];
				for (int j=head[u];j;j=e[j].ne)
					if (e[j].w>e[j].f) minn=min(minn,d[e[j].v]);
				d[u]=minn+1; ++gap[d[u]];
				if (u!=ss) u=e[pre[u]^1].v;
			}
		}
		return ans;
	}
};
ISAP<1000, 1000000> Sap;
int n,f[1010],a[1010],ans1,ans2,T,S;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;++i)	scanf("%d",&a[i]);
	memset(f,0,sizeof(f)); ans1=0;
	for (int i=1;i<=n;++i)
	{
		f[i]=1;
		for (int j=1;j<i;++j) if (a[j]<a[i]) f[i]=max(f[i],f[j]+1);
		ans1=max(ans1,f[i]);
	} 
	printf("%d\n",ans1);
	T=2*n+1; S=0;
	for (int i=1;i<=n;++i) 
	{
		if (f[i]==1) Sap.build(S,i,1);
		if (f[i]==ans1) Sap.build(i+n,T,1);
		Sap.build(i,i+n,1);
	}
	for (int i=1;i<=n;++i)
		for (int j=i+1;j<=n;++j)
			if (a[i]<a[j] && f[i]==f[j]-1)	Sap.build(i+n,j,1);
	printf("%d\n",Sap.isap(S,T,Sap.tot));
	Sap.cl();
	for (int i=1;i<=n;++i)
	{
		int tmp=1;
		if (i==1 || i==n) tmp=INF;
		if (f[i]==1) Sap.build(S,i,tmp);
		if (f[i]==ans1) Sap.build(i+n,T,tmp);
		Sap.build(i,i+n,tmp);
	}
	for (int i=1;i<=n;++i)
		for (int j=i+1;j<=n;++j)
			if (a[i]<a[j] && f[i]==f[j]-1) Sap.build(i+n,j,1);
	ans2=Sap.isap(S,T,Sap.tot);
	if (ans2>=INF) printf("%d\n",n); else printf("%d\n",ans2);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值