Wormhole Transport - ZOJ 3613 斯坦纳树

23 篇文章 1 订阅

Wormhole Transport

Time Limit: 3 Seconds       Memory Limit: 65536 KB

Wormhole is a kind of two-way tunnel between two planets which can make it possible to transport large amounts of resources without time. Of course, building Wormhole has lots of requirements, only some pairs of the planet can build Wormhole and it costs lots of money. Country G is a very big country which has a lot of planets. There are several resource planets in country G. One resource planet can provide for a factory, and a factory need a resource planet to provide resource. Due to various reasons, country G has build some factories in several planets without considering about resource planets. So it depends on Wormhole to transport resource if a factory can't get resource from local. It is your task to make a plan to build Wormholes which can make most factories run and use the least money in this case.

Input

The input consist of multiple cases. For each test case, the first line contains an integer N (0 < N ≤ 200) which indicates the number of planets in country G. Then followed by Nlines, each line contains two integers PiSi .Pi is the number of factories in planet i, if Si =1, planet i is a resource planet; if Si =0, planet i isn't a resource planet. At most of 4 planets have factories and at most of 4 planets are resource planets. The next line contains an integer M (0 < M ≤ 5000) which indicates the number of pairs of planet which can build Wormhole. Then followed by M lines, each line contains three integers xiyici, which indicate building Wormhole between planet xi and planet yi costs ci.

Output

The output contains one line per case. It contains the maximum of factories that can get resource and the the minimum of money when the maximum of factories that can get resource.

Sample Input
2
1 0
0 1
1
1 2 3
Sample Output
1 3

思路:我是渣渣,初学者,讲不好,就不误导大家了,仅仅贴出代码供自己借鉴。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define MAX 5010
#define MIN 1010
#define INF 1e9
queue<int> qu;
struct planet
{ int a,b;
}arr[MIN];
struct node
{ int v,len;
  node *next;
}*head[MAX*2],tree[MAX*2];
bool in[MIN][MIN];
int cost[MIN][MIN],n,nn,k,tot,m,dp[MIN],st[MIN],fac[MIN],res[MIN],orik,ptr,ans,ansi,num;
void init()
{ int i,j,t;
  ptr=0;
  orik=k;
  memset(st,0,sizeof(st));
  memset(in,0,sizeof(in));
  memset(head,NULL,sizeof(head));
  for(i=0;i<tot;i++)
   res[k++]=fac[i];
  nn=1<<k;
  for(j=0;j<n;j++)
   for(i=0;i<nn;i++)
    cost[j][i]=INF;
  for(i=0;i<k;i++)
  { st[res[i]]=1<<i;
    cost[res[i]][st[res[i]]]=0;
  }
}
void AddEdge(int a,int b,int c)
{ tree[ptr].v=b;
  tree[ptr].len=c;
  tree[ptr].next=head[a];
  head[a]=&tree[ptr++];
}
void Spfa()
{ int i,j,v,nst,len;
  while(!qu.empty())
  { j=qu.front()/MAX;
    i=qu.front()%MAX;
    qu.pop();
    in[j][i]=false;
    node *p=head[j];
    while(p!=NULL)
    { v=p->v;
      len=p->len;
      nst=i|st[v];
      if(cost[j][i]+len<cost[v][nst])
      { cost[v][nst]=cost[j][i]+len;
        if(nst==i && !in[v][nst])
        { qu.push(v*MAX+nst);
          in[v][nst]=true;
        }
      }
      p=p->next;
    }
  }
}
void Steiner_Tree()
{ int i,j,t,s;
  for(i=0;i<nn;i++)
  { for(j=0;j<n;j++)
    { if(st[j] && !(st[j]&i))
       continue;
      for(t=(i-1)&i;t;t=(t-1)&i)
       cost[j][i]=min(cost[j][i],cost[j][t|st[j]]+cost[j][(i-t)|st[j]]);
      if(cost[j][i]<INF)
      { qu.push(j*MAX+i);
        in[j][i]=true;
      }
    }
    Spfa();
  }
}
bool Check(int s)
{ int i,cnt=0;
  for(i=0;i<orik;i++)
   if(s&(1<<i))
    cnt++;
  for(i=orik;i<k;i++)
   if(s&(1<<i))
    cnt-=arr[fac[i-orik]].a;
  return cnt<=0;
}
void Solve_DP()
{ int i,j,t;
  for(i=0;i<nn;i++)
  { dp[i]=INF;
    for(j=0;j<n;j++)
     dp[i]=min(dp[i],cost[j][i]);
  }
  for(i=0;i<nn;i++)
   if(Check(i))
    for(t=(i-1)&i;t;t=(t-1)&i)
     if(Check(t) && Check(i-t))
      dp[i]=min(dp[i],dp[t]+dp[i-t]);
  for(i=0;i<nn;i++)
   if(dp[i]<INF && Check(i))
   { int cnt=0;
     for(j=0;j<orik;j++)
      if(i&(1<<j))
       cnt++;
     if(cnt>ans)
     { ans=cnt;
       ansi=dp[i];
     }
     else if(cnt==ans)
      ansi=min(ansi,dp[i]);
   }
}
int main()
{ int t,i,j,a,b,c;
  while(~scanf("%d",&n))
  { ans=ansi=0;
    num=k=tot=0;
    for(i=0;i<n;i++)
    { scanf("%d%d",&arr[i].a,&arr[i].b);
      if(arr[i].a && arr[i].b)
      { num++;
        arr[i].a--;
        arr[i].b--;
      }
      if(arr[i].a)
       fac[tot++]=i;
      if(arr[i].b)
       res[k++]=i;
    }
    init();
    scanf("%d",&m);
    while(m--)
    { scanf("%d%d%d",&a,&b,&c);
      a--;b--;
      AddEdge(a,b,c);
      AddEdge(b,a,c);
    }
    Steiner_Tree();
    Solve_DP();
    printf("%d %d\n",ans+num,ansi);
  }
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值