hdu 3996 Gold Mine (最大权闭合图)

这题卡数据!!!没意义:
题目大意:本题描述比较模糊,我重新描述下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 
 
不理解的没卡的两个代码,说inf开大了,明显扯蛋 :
 
 
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;
}

AC sap版 :
 

#include <cstdio>
#include <string.h>

using namespace std;

typedef long long ll;
const int N=3550;
const int M=9000000;
const ll inf=13216546513113211ll;

int head[N];

struct Edge{
    int v,next;
    ll w;
} edge[M];

int cnt,s=0;

void addedge(int u,int v,ll w)//这里存的还是一条有向边
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}

ll sap(int t){
    int pre[N],cur[N],dis[N],gap[N];
    ll flow=0,aug=inf,u;
    bool flag;
    for(int i=0; i<=t; i++){
        cur[i]=head[i];
        gap[i]=dis[i]=0;
    }
    gap[s]=t+1;
    u=pre[s]=s;
    while(dis[s]<=t){
        flag=0;
        for(int &j=cur[u]; ~j; j=edge[j].next){
            int v=edge[j].v;
            if(edge[j].w>0&&dis[u]==dis[v]+1){
               flag=1;
               if(edge[j].w<aug) aug=edge[j].w;
               pre[v]=u;
               u=v;
               if(u==t){
                    flow+=aug;
                    //printf("%d\n",flow);
                    while(u!=s){
                       u=pre[u];
                       edge[cur[u]].w-=aug;
                       edge[cur[u]^1].w+=aug;//异或是找与其配对的边
                    }
                    aug=inf;
                }
                break;
            }
        }
        if(flag) continue;
        int mindis=t+1;
        for(int j=head[u]; ~j; j=edge[j].next){
            int v=edge[j].v;
            if(edge[j].w>0&&dis[v]<mindis){
                mindis=dis[v];
                cur[u]=j;
            }
        }
        if((--gap[dis[u]])==0)
            break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return flow;
}

ll value[N];
void init()
{
    memset (head , -1 , sizeof(head));
    cnt=0;
}

int main ()
{
    int cas;
    int n,lay,c;
    ll a,b;
    ll sum=0;
    int u,v;
    scanf("%d",&cas);
    for (int I=1 ; I<=cas ; ++I)
    {
        init();
        sum=0;
        scanf("%d",&lay);
        for (int i=0 ; i<lay ; ++i)
        {
            scanf("%d",&n);
            for (int j=0 ; j<n ; ++j)
            {
                scanf("%I64d%I64d%d",&a,&b,&c);
                value[i*25+j+1]=b-a;
                for (int k=0 ; k<c ; ++k)
                {
                    scanf("%d%d",&u,&v);
                    u--;v--;
                    addedge(i*25+j+1,u*25+v+1,inf);
                }
                if(value[i*25+j+1]>0)
                    addedge(0,i*25+j+1,value[i*25+j+1]),sum+=value[i*25+j+1];
                if(value[i*25+j+1]<0)
                    addedge(i*25+j+1,2550,-value[i*25+j+1]);
            }
        }
        ll  ans=sum-sap(2550);
        //printf("%d\n",sum);
        printf("Case #%d: %I64d\n",I,ans);
    }
    return 0;
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值