hdu 3996 Gold Mine

Gold Mine

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1464    Accepted Submission(s): 335


Problem Description
Long long ago, there is a gold mine.The mine consist of many layout, so some area is easy to dig, but some is very hard to dig.To dig one gold, we should cost some value and then gain some value. There are many area that have gold, because of the layout, if one people want to dig one gold in some layout, he must dig some gold on some layout that above this gold's layout. A gold seeker come here to dig gold.The question is how much value the gold he can dig, suppose he have infinite money in the begin.
 

Input
First line the case number.(<=10)

Then for every case:
  one line for layout number.(<=100)
  for every layout
  first line gold number(<=25)
  then one line for the dig cost and the gold value(32bit integer), the related gold number that must be digged first(<=50)

then w lines descripte the related gold followed, each line two number, one layout num, one for the order in that layout
see sample for details
 

Output
Case #x: y.
x for case number, count from 1.
y for the answer.
 

Sample Input
  
  
1 2 1 10 100 0 2 10 100 1 1 1 10 100 1 1 1
 

Sample Output
  
  
Case #1: 270
 

Source

题目大意:本题描述比较模糊,我重新描述下Input:
                 第一行:T表示测试组数(T<=10),接下来T组测试数据,每组包括
                         第一行:n(n<=100),表示有n个金矿区(暂且称为金矿区,每个金矿区有若干个采矿点)
                         接下来有n组数据,每组描述每个金矿区情况:
                         对于第i组,第一行输入m(m<=25),表示第i(1=<i<=n)个金矿区有m个采矿点
                                             接下来又有m组数据,每组描述该金矿区的某个采矿点情况:
                                             对于第j组,输入cost(开采费用),val(开采后能获利),w(开采此采矿点前必须要开采其他m个采矿点)
                                                                 接下来w行,每行两个整数a,b,表示必须先开采第a个金矿区的第b个采矿点。
分析:比较明显的最大闭合权图。 
          建图: 
          如果某个金矿的开发利润为正值,就在源点和该点之间连一条容量为该利润的边 
          如果某个金矿的开发利润为负值,就在该点和汇点之间连一条容量为该利润绝对值的边 
          如果某个金矿收到另一个金矿的限制,就在两个金矿之间连一条容量为INF的边。 
          累计所有正值利润的和  sum,获得的最大利润为sum - ans 

代码:
dinic
#include<cstdio>
#include<cstring>
#define ll __int64
const int N=2505;
const int M=72600;
const ll INF=10000000000;
int tol,n,s,t;
ll ans;
int head[N],d[N];
struct node
{
	ll f;
    int y,nxt;
}edge[M];
ll min(ll a,ll b){return a<b?a:b;}
void add(int x,int y,ll f)
{
    edge[tol].y=y;
    edge[tol].f=f;
    edge[tol].nxt=head[x];
    head[x]=tol++;
    edge[tol].y=x;
    edge[tol].f=0;
    edge[tol].nxt=head[y];
    head[y]=tol++;
}
bool bfs()
{
	int front=0,rear=0,q[N],u,v,i;
	memset(d,-1,sizeof(d));
	d[s]=0;
	q[rear++]=s;
	while(front<rear)
	{
		u=q[front++];
		for(i=head[u];i!=-1;i=edge[i].nxt)
		{
			v=edge[i].y;
			if(edge[i].f&&d[v]==-1)
			{
				d[v]=d[u]+1;
				if(v==t)return 1;
				q[rear++]=v;
			}
		}
	}
	return 0;
}
ll dfs(int s,ll limit)
{
	if(s==t)return limit;
	int i,v;
	ll sum=0,tmp;
	for(i=head[s];i!=-1;i=edge[i].nxt)
	{
		v=edge[i].y;
		if(edge[i].f&&d[s]+1==d[v])
		{
			tmp=dfs(v,min(limit-sum,edge[i].f));
			edge[i].f-=tmp;
			edge[i^1].f+=tmp;
			sum+=tmp;
			if(limit==sum)return sum;
		}
	}
	if(sum==0)d[s]=-1;
	return sum;
}
void dinic(){while(bfs())ans+=dfs(s,INF);}
int main()
{
	int T,ca=1,i,j,a,b,m,w,val,cost;
	ll sum;
	scanf("%d",&T);
	while(T--)
	{
		memset(head,-1,sizeof(head));
		scanf("%d",&n);
		s=0,t=n*25+1;tol=0,ans=0;sum=0;
		for(i=0;i<n;i++)
		{
			scanf("%d",&m);
			for(j=1;j<=m;j++)
			{
				scanf("%d%d%d",&cost,&val,&w);
				val-=cost;
				if(val>0){add(s,i*25+j,val);sum+=val;}
				else add(i*25+j,t,-val);
				while(w--)
				{
					scanf("%d%d",&a,&b);
					add(i*25+j,(a-1)*25+b,INF);
				}
			}
		}
		dinic();
		printf("Case #%d: %I64d\n",ca++,sum-ans);
	}
	return 0;
}


sap
#include<cstdio>
#include<cstring>
#define ll __int64
const int N=2505;
const int M=72600;
const ll INF=10000000000;
int n,s,t,tol;
ll ans;
int head[N],arc[N],pre[N],dis[N],gap[N];
struct node
{
	ll f;
	int y,nxt;
}edge[M];
void add(int x,int y,ll f)
{
	edge[tol].y=y;
	edge[tol].f=f;
	edge[tol].nxt=head[x];
	head[x]=tol++;
	edge[tol].y=x;
	edge[tol].f=0;
	edge[tol].nxt=head[y];
	head[y]=tol++;
}
void sap()
{
	memset(dis,0,sizeof(dis));
	memset(gap,0,sizeof(gap));
	memcpy(arc,head,sizeof(head));
	gap[0]=n;
	ll arg=INF;
	int u=pre[s]=s;
	while(dis[s]<n)
	{
L:
		for(int& i=arc[u];i!=-1;i=edge[i].nxt)
		{
			int v=edge[i].y;
			if(edge[i].f&&dis[u]==dis[v]+1)
			{
				if(arg>edge[i].f)arg=edge[i].f;
				pre[v]=u;u=v;
				if(v==t)
				{
					ans+=arg;
					for(u=pre[u];v!=s;v=u,u=pre[u])
					{
						edge[arc[u]].f-=arg;
						edge[arc[u]^1].f+=arg;
					}
					arg=INF;
				}
				goto L;
			}
		}
		int min=n;
		for(int j=head[u];j!=-1;j=edge[j].nxt)
		{
			int v=edge[j].y;
			if(edge[j].f&&min>dis[v])
			{
				arc[u]=j;
				min=dis[v];
			}
		}
		if(--gap[dis[u]]==0)break;
		dis[u]=min+1;
		gap[dis[u]]++;
		u=pre[u];
	}
}
int main()
{
	int T,ca=1,i,j,a,b,m,w,cost,val;
	ll sum;
	scanf("%d",&T);
	while(T--)
	{
		memset(head,-1,sizeof(head));
		scanf("%d",&n);
		s=0,t=n*25+1;tol=0,ans=0;sum=0;
		for(i=0;i<n;i++)
		{
			scanf("%d",&m);
			for(j=1;j<=m;j++)
			{
				scanf("%d%d%d",&cost,&val,&w);
				val-=cost;
				if(val>0){add(s,i*25+j,val);sum+=val;}
				else add(i*25+j,t,-val);
				while(w--)
				{
					scanf("%d%d",&a,&b);
					add(i*25+j,(a-1)*25+b,INF);
				}
			}
		}
		n=t+1;
		sap();
		printf("Case #%d: %I64d\n",ca++,sum-ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值