poj3469 - Dual Core CPU

133 篇文章 0 订阅

                               想看更多的解题报告:http://blog.csdn.net/wangjian8006/article/details/7870410
                                  转载请注明出处:
http://blog.csdn.net/wangjian8006

题目大意:有两个CPU,现在又n个任务,任务在第A个CPU里面执行所花费Ai代价,在第B个CPU里面执行所花费Bi代价
然后又m个限制,每个限制是a,b,c,说任务a和任务b如果不在一个CPU执行就会多花费c代价。

解题思路:基本上看分成2部分就可以直觉感觉是求最小割,割值就是在平面画一条直线,将所有点分为两部分,然后算图上和这条直线相交的边的权值和。而对于最小割来说,最大流流量就是最小割的容量。
而划分方法,就是将最大流后残余网络中s可以走到的点划为s集合,其余点划为t集合,注意,不是可以走到t的点,因为有可能有一条线上的多条边都流满的情况,这种情况下有些点就无法走到t,而且s也走不到它。

这样建图:一个超级源点指向所有任务,容量为任务点在A上所花的代价,反向边容量为0

然后所有任务点指向一个超级汇点,容量为任务点在B上所花的代价,反向边容量为0
然后多花费代价c,就让a和b之间连一条边,来回的容量都为c

 

/*
dinic+邻接表
Memory 9952K
Time  4844MS
*/
#include <iostream>
#include <queue>
using namespace std;
#define INF INT_MAX
#define MAXE 500000
#define MAXV 20100
#define min(a,b) (a>b?b:a)

typedef struct{
	int s,t,r,contrary,next;
}Edge;
Edge edge[MAXE];
int n,m,source,sink,edge_sum,maxflow;
int head[MAXV],dis[MAXV];

void addedge(int x,int y,int c,int flag){
	edge[edge_sum].s=x;
	edge[edge_sum].t=y;
	edge[edge_sum].r=c;
	edge[edge_sum].contrary=edge_sum+1;
	edge[edge_sum].next=head[x];
	head[x]=edge_sum++;
	edge[edge_sum].s=y;
	edge[edge_sum].t=x;
	edge[edge_sum].contrary=edge_sum-1;
	edge[edge_sum].r=(flag?c:0);
	edge[edge_sum].next=head[y];
	head[y]=edge_sum++;
}

int bfs(){
	int i,v,tmp;
	queue <int>q;
	memset(dis,0,sizeof(dis));
	dis[source]=1;
	q.push(source);
	while(!q.empty()){
		v=q.front();q.pop();
		for(i=head[v];i!=-1;i=edge[i].next){
			tmp=edge[i].t;
			if(!dis[tmp] && edge[i].r){
				dis[tmp]=dis[v]+1;
				if(tmp==sink) return 1;
				q.push(tmp);
			}
		}
	}
	return 0;
}

int dfs(int cur,int cp){
	if(cur==sink) return cp;

	int tmp=0,i,a,t;
	for(i=head[cur];i!=-1 && tmp<cp;i=edge[i].next){
		a=edge[i].t;
		if(dis[a]==dis[cur]+1 && edge[i].r){
			t=dfs(a,min(edge[i].r,cp-tmp));
			edge[i].r-=t;
			edge[edge[i].contrary].r+=t;
			tmp+=t;
		}
	}
	if (!tmp) dis[cur]=-1;		//这里代表流已经没了,或者说此路不通
	return tmp;
}

void dinic(){
	maxflow=0;
	while(bfs()) maxflow+=dfs(source,INF);
}

int main(){
	int i,a,b,c;
	while(~scanf("%d%d",&n,&m)){
		source=0;sink=n+1,edge_sum=0;
		memset(head,-1,sizeof(head));
		for(i=1;i<=n;i++){
			scanf("%d%d",&a,&b);
			addedge(source,i,a,0);		//这是连的有向边
			addedge(i,sink,b,0);
		}
		for(i=0;i<m;i++){
			scanf("%d%d%d",&a,&b,&c);
			addedge(a,b,c,1);			//这里连无向边
		}
		dinic();
		printf("%d\n",maxflow);
	}
	return 0;
}


 

==========================================================================================================

 

 

/*
sap+gap+邻接表
Memory 8080K
Time  2375MS
*/
#include <iostream>
using namespace std;
#define INF INT_MAX
#define MAXE 500000
#define MAXV 20100
#define min(a,b) (a>b?b:a)

typedef struct{
	int t,r,contrary,next;
}Edge;
Edge edge[MAXE];
int n,m,source,sink,edge_sum,maxflow;
int head[MAXV],dis[MAXV],cur[MAXV],gap[MAXV],pre[MAXV];

void addedge(int x,int y,int c,int flag){
	edge[edge_sum].t=y;
	edge[edge_sum].r=c;
	edge[edge_sum].next=head[x];
	head[x]=edge_sum++;
	edge[edge_sum].t=x;
	edge[edge_sum].r=(flag?c:0);
	edge[edge_sum].next=head[y];
	head[y]=edge_sum++;
}

void sap(){
	int u=pre[source]=source,tmp=INF,v,a;
	memset(dis,0,sizeof(dis));
	memset(gap,0,sizeof(gap));

	for(v=0;v<=n;v++) cur[v]=head[v];

	gap[source]=n;
	maxflow=0;

	while(dis[source]<n){
loop:
		for(v=cur[u];v!=-1;v=edge[v].next){
			a=edge[v].t;
			if(dis[u]==dis[a]+1 && edge[v].r>0){
				cur[u]=v;
				tmp=min(tmp,edge[v].r);
				pre[a]=u;
				u=a;
				if(u==sink){
					while(u!=source){
						u=pre[u];
						edge[cur[u]].r-=tmp;
						edge[cur[u]^1].r+=tmp;
					}
					maxflow+=tmp;
					tmp=INF;
				}
				goto loop;
			}
		}

		int mind=n;
		for(v=head[u];v!=-1;v=edge[v].next){
			a=edge[v].t;
			if(edge[v].r>0 && mind>dis[a]){
				cur[u]=v;
				mind=dis[a];
			}
		}

		if((--gap[dis[u]])==0) break;

		gap[dis[u]=mind+1]++;
		u=pre[u];
	}
}

int main(){
	int i,a,b,c;
	while(~scanf("%d%d",&n,&m)){
		source=0;sink=n+1,edge_sum=0;
		memset(head,-1,sizeof(head));
		for(i=1;i<=n;i++){
			scanf("%d%d",&a,&b);
			addedge(source,i,a,0);		//这是连的有向边
			addedge(i,sink,b,0);
		}
		for(i=0;i<m;i++){
			scanf("%d%d%d",&a,&b,&c);
			addedge(a,b,c,1);			//这里连无向边
		}
		n+=2;
		sap();
		printf("%d\n",maxflow);
	}
	return 0;
}


 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值