poj 3469

哎,被这道题搞死啦,详细解释在代码中

//最小割模型。首先建网络流模型,建立源点s和终点t(分别代表这两块不同的芯片),然后把s和每个点之间连一条容量为1,方向从s到点的边(方向
//一定要确定,因为割的容量的定义),然后从每个点到终点连一条容量为1,方向为点到t的边,然后在有联系的
//两点之间建一条容量为1的无向边(即一对容量为1方向相反的有向边)。建图完成。那么,在这个网络流模型中的一个割
//就对应于一种选择方案,而此方案的花费即割的容量。原因如下:先看所有的点都没有联系的情况,那么所有点和s的边
//和t的边这两条边有且仅有一条边在割去的边的集合中,哪条边割去说明点在哪个芯片上,那么割的容量就等于总花费(根
//据我们所建的模型)。说明一个割就是一种方案。然后考虑有有联系的点。对于一对有联系的点如果选择了同一块芯片,那么
//他们之间的那对相反方向的边就不在割去的边的集合中,所以此时总的花费也是等于割的容量。如果选择了不同的芯片,那么
//他们之间的边就在割去的边的集合中,此时总的花费也等于个的容量。注意此时,那对双向边的容量并没有造成花费的重复计算
//因为割的容量只是所有从s到t的边的容量值和,那两条双向边中只有一条是算在容量中,这也是为什么连接双向而不是单项边的
//原因,因为单向边会造成割的容量小于实际花费,两个点之间的花费没有算在割的容量中。所以此题求最小花费就是求最小割的容量,
//也即最大流的大小。数据量很大,用的是Dinic
	#include <iostream>
	#include <cstring>
	#include <cstdio>
	#include <queue>
	using namespace std;
	const int maxn=20003;
	const int maxe=900000;
	const int inf=1<<25;
	struct Edge
	{
		int from,to,next;
	};
	Edge edges[maxe];
	int p[maxn],num[maxn],flow[maxe],cap[maxe],d[maxn],cur[maxn],head[maxn]; 
	int n,m,tot,s,t;
	bool bfs()
	{
		memset(d,-1,sizeof(d));
		queue<int> q;
		q.push(s);
		d[s]=0;
		while(!q.empty())
		{
			int x=q.front();q.pop();
			for(int i=head[x];i!=-1;i=edges[i].next)
			{
				Edge& e=edges[i];
				if(d[e.to]==-1&&cap[i]>flow[i])
				{
					d[e.to]=d[x]+1;
					q.push(e.to);
				}
			}
		}
		if(d[t]!=-1) return true;
		else return false;
	}
	int dfs(int x,int a)
	{
		if(x==t||a==0) return a;
		int tflow=0,f;
		for(int i=cur[x];i!=-1;i=edges[i].next)
		{
			Edge& e=edges[i];
			if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,cap[i]-flow[i])))>0)
			{
				flow[i]+=f;
				flow[i^1]-=f;
				tflow+=f;
				a-=f;
				if(a==0) break;
			}
		}
		return tflow;
	}
	int maxflow()
	{
		int tflow=0;
		while(bfs())
		{
			memcpy(cur,head,(n+2)*sizeof(int));
			tflow+=dfs(s,inf);
		}
		return tflow;
	}
	void addedge(int from,int to,int ecap)
	{
		edges[tot].from=from;
		edges[tot].to=to;
		cap[tot]=ecap;
		edges[tot].next=head[from];
		head[from]=tot;
		tot++;
		edges[tot].from=to;
		edges[tot].to=from;
		cap[tot]=0;
		edges[tot].next=head[to];
		head[to]=tot;
		tot++;
	}
	void init()
	{
		tot=0;
		memset(flow,0,sizeof(flow));
		memset(cap,0,sizeof(cap));
		memset(head,-1,sizeof(head));
	}
	int main()
	{
		while(scanf("%d%d",&n,&m)!=EOF)
		{
			s=0;t=n+1;
			int i,j,ga,gb,a,b,w;
			init();
			for(i=1;i<=n;i++)
			{
				scanf("%d%d",&ga,&gb);
				addedge(0,i,ga);
				addedge(i,n+1,gb);
			}
			for(i=1;i<=m;i++)
			{
				scanf("%d%d%d",&a,&b,&w);
				addedge(a,b,w);
				addedge(b,a,w);
			}
			printf("%d\n",maxflow());
		}
		return 0;
	}
		


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值