zoj2676 Network Wars 0-1分数规划 最小割的应用

题意:给定一个带权无向图G(V,E),每条边有个权值w,求将点s和点t分开的一个边割集C,使该割集的平均边权最小。

思路:参见Amber的《最小割模型在信息学竞赛中的应用》。大体就是构造新函数g(x),找到g(x)=0的x,x即为平均边权最小值。

// file name: zoj2676.cpp //
// author: kereo //
// create time:  2014年10月31日 星期五 15时33分36秒 //
//***********************************//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int sigma_size=26;
const int MAXN=500+100;
const double eps=1e-6;
const int inf=0x7fffffff;
const int mod=1000000000+7;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
int n,m,edge_cnt,top;
int que[MAXN],s[MAXN];
int head[MAXN],depth[MAXN],cur[MAXN],gap[MAXN],vis[MAXN];
struct node{
	int u,v;
	double w;
}p[MAXN];
struct Edge{
	int v,next;
	double cap,flow;
}edge[MAXN<<1];
void init(){
	edge_cnt=top=0;
	memset(head,-1,sizeof(head));
}
void addedge(int u,int v,double w){
	edge[edge_cnt].v=v;
	edge[edge_cnt].cap=w; edge[edge_cnt].flow=0;
	edge[edge_cnt].next=head[u]; head[u]=edge_cnt++;
}
void bfs(int st,int ed){
	memset(depth,-1,sizeof(depth));
	memset(gap,0,sizeof(gap));
	int front=0,rear=0; gap[0]=1;
	depth[ed]=0; que[rear++]=ed;
	while(front!=rear){
		int u=que[front++];
		for(int i=head[u];i!=-1;i=edge[i].next){
			int v=edge[i].v;
			if(depth[v]!=-1) continue;
			que[rear++]=v;
			depth[v]=depth[u]+1; gap[depth[v]]++;
		}
	}
}
double isap(int st,int ed){
	bfs(st,ed);
	memcpy(cur,head,sizeof(head));
	top=0;
	int u=st;
	double ans=0;
	while(depth[st]<n){
		if(u == ed){
			double Min=inf;
			int inser;
			for(int i=0;i<top;i++){
				if(edge[s[i]].cap-edge[s[i]].flow+eps<Min){
					Min=edge[s[i]].cap-edge[s[i]].flow;
					inser=i;
				}
			}
			for(int i=0;i<top;i++){
				edge[s[i]].flow+=Min; edge[s[i]^1].flow-=Min;
			}
			ans+=Min; top=inser;
			u=edge[s[top]^1].v;
			continue;
		}
		int flag=0;
		int v;
		for(int i=cur[u];i!=-1;i=edge[i].next){
			v=edge[i].v;
			if(edge[i].flow+eps<edge[i].cap && depth[v]+1 == depth[u]){
				flag=1; cur[u]=i;
				break;
			}
		}
		if(flag){
			s[top++]=cur[u]; u=v;
			continue;
		}
		int d=n;
		for(int i=head[u];i!=-1;i=edge[i].next){
			int v=edge[i].v;
			if(edge[i].flow+eps<edge[i].cap && depth[v]<d){
				d=depth[v];
				cur[u]=i;
			}
		}
		gap[depth[u]]--;
		if(!gap[depth[u]]) return ans;
		depth[u]=d+1; gap[depth[u]]++;
		if(u!=st) u=edge[s[--top]^1].v;
	}
	return ans;
}
void dfs(int u){
	for(int i=head[u];i!=-1;i=edge[i].next){
		int v=edge[i].v;
		if(edge[i].flow+eps<edge[i].cap && !vis[v]){
			vis[v]=1;
			dfs(v);
		}
	}
}
void solve(){
	double l=0,r=1e7,mid;
	while(l+eps<r){
		mid=(l+r)/2;
		double ans=0;
		init();
		for(int i=1;i<=m;i++){
			if(p[i].w+eps<mid)
				ans+=p[i].w-mid;
			else{
				addedge(p[i].u,p[i].v,p[i].w-mid);
				addedge(p[i].v,p[i].u,p[i].w-mid);
			}
		}
		ans+=isap(1,n);
		if(ans>eps)
			l=mid;
		else 
			r=mid;
	}
	memset(vis,0,sizeof(vis));
	vis[1]=1;
	dfs(1);
	int res=0;
	for(int i=1;i<=m;i++){
		if(p[i].w+eps<mid || (vis[p[i].u]+vis[p[i].v]) == 1)
			res++;
	}
	printf("%d\n",res);
	int flag=1;
	for(int i=1;i<=m;i++){
		if(p[i].w+eps<mid || (vis[p[i].u]+vis[p[i].v]) == 1){
			if(flag){
				printf("%d",i);
				flag=0;
			}
			else
				printf(" %d",i);
		}
	}
	printf("\n");
}
int main()
{
	int flag=0;
	while(~scanf("%d%d",&n,&m)){
		if(!flag)
			flag=1;
		else 
			printf("\n");
		for(int i=1;i<=m;i++)
			scanf("%d%d%lf",&p[i].u,&p[i].v,&p[i].w);
		solve();
	}
	return 0;

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值