hdu3879及ISAP模板(链式前向星)

题意不多说了,解题思路详见胡波涛的《最小割模型在信息学竞赛的应用》论文。

复习了一下链式前向星,虽然都是ISAP,但是写起来还是有许多要注意的地方。详细见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#define rep(i,a,b)	for (int i=a;i<(b+1);i++)
using namespace std;
const int maxn=60000;
const int maxm=600000;
const int inf=1<<28;
int n,m,cnt,head[maxn],pnt[maxm],nxt[maxm],flow[maxm],pre[maxn],d[maxn],iter[maxn],gap[maxn],s,t;
bool vis[maxn]={false};
void addedge(int u,int v,int f){
	pnt[cnt]=v;nxt[cnt]=head[u];flow[cnt]=f;head[u]=cnt++;
	pnt[cnt]=u;nxt[cnt]=head[v];flow[cnt]=0;head[v]=cnt++;
}
void spfa(){
	memset(d,-1,sizeof d);
	memset(vis,false,sizeof vis);
	queue<int> q;
	q.push(t);
	vis[t]=true;
	d[t]=0;
	while (!q.empty()){
		int u=q.front();
		q.pop();
		for (int i=head[u];i!=-1;i=nxt[i])
			if (!vis[pnt[i]]&&flow[i^1]>0){
				vis[pnt[i]]=true;
				d[pnt[i]]=d[u]+1;
				q.push(pnt[i]);
			}
	}
}
int augement(){
	int f=0x3f3f3f3f;
	for (int i=pre[t];i!=-1;i=pre[pnt[i]])	f=min(f,flow[i^1]);
	for (int i=pre[t];i!=-1;i=pre[pnt[i]]){
		flow[i^1]-=f;
		flow[i]+=f;
	}
	return f;
}
int Max_flow(){
	int fl=0;
	spfa();
	memset(gap,0,sizeof gap);
	memset(pre,-1,sizeof pre);
	rep(i,0,t)	iter[i]=head[i];
	rep(i,0,t)	if (~d[i])	gap[d[i]]++;
	int u=0;
	while (d[0]<(t+1)){
		if (u==t){
			fl+=augement();
			u=0;
		}
		bool adv=false;
		for (int &i=iter[u];i!=-1;i=nxt[i])	if (flow[i]&&d[u]==d[pnt[i]]+1){
			adv=true;
			pre[pnt[i]]=i^1;
			u=pnt[i];
			break;
		}
		if (!adv){
			int m=t+1;
			for (int i=head[u];i!=-1;i=nxt[i])	if (flow[i]&&~d[pnt[i]])	m=min(m,d[pnt[i]]);
			if (--gap[d[u]]==0)	break;
			d[u]=m+1;
			gap[d[u]]++;
			iter[u]=head[u];
			if (u!=0)	u=pnt[pre[u]];
		}
	}
	return fl;
}
int main(){
	while (~scanf("%d%d",&n,&m)){
		cnt=0;
		memset(pnt,0,sizeof pnt);
		memset(nxt,-1,sizeof nxt);
		memset(flow,0,sizeof flow);
		memset(head,-1,sizeof head);
		s=0,t=n+m+1;
		rep(i,1,n){
			int x;
			scanf("%d",&x);
			addedge(m+i,t,x);
		}
		int sum=0;
		rep(i,1,m){
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			addedge(s,i,c);
			addedge(i,a+m,inf);
			addedge(i,b+m,inf);
			sum+=c;
		}
		printf("%d\n",sum-Max_flow());
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值