CEOI2008 order

申请了博客不发点东西总觉得不太好

虽然这个题是CEOI的题,但是时间有点久远,现在看来是一道网络流很好的练手题。

透过现象看本质,我们可以发现,每台机器只有租或者买两个选项,且只能二选一,这种二选一,每种选择还有不同权值的东西,我们可以大胆猜测是要求最小割,然后手动画图手玩一下就会发现果然没错。

然后就是建图,网络流的题一般来说只要找到建图的方法,剩下的就是无脑套板子了,所以我们需要思考建图方案。而这对于本蒟蒻来说,简直困难到炸(适当装弱有益健康)。

源点向所有工作连边,权值为收益;工作向机器连边,权值为租用费用;机器向汇点连边,权值为购买费用。

剩下的就是最小割板子了。

(吐槽一下当初我看的那一篇讲dinic的文章,附的板子奇慢无比。。。水题都会T,我还以为是我自带巨大常数(虽然确实我自带巨大常数)。。。)

//made by Crazy01
#include<map>
#include<queue>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define inf 1<<30
#define LL long long
#define c233 cout<<"233"<<endl
#define mem(s) memset(s,0,sizeof(s))
#define M 4500000
#define N 4050
#define il inline
using namespace std;

int nxt[M],t[M],w[M],head[N],dis[N],que[N];
int n,m,maxe=1,S,T,all,hd,tl;

il int min(int x,int y){
  return x<y?x:y;
}

il int gi(){
  int x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}

il void build(int a,int b,int c){
  nxt[++maxe]=head[a];t[maxe]=b;w[maxe]=c;head[a]=maxe;
  nxt[++maxe]=head[b];t[maxe]=a;w[maxe]=0;head[b]=maxe;
}

il void init(){
  n=gi();m=gi();
  S=0;T=m+n+1;
  for(int i=1;i<=n;i++){
    int a=gi(),b=gi();
    build(S,i,a);
    all+=a;
    for(int j=1;j<=b;j++){
      int x=gi(),y=gi();
      build(i,x+n,y);
    }
  }
  for(int i=1;i<=m;i++){
    int x=gi();
    build(i+n,T,x);
  }
}

il bool bfs(){
  hd=tl=0;
  for(int i=S;i<=T;i++)dis[i]=-1;
  dis[S]=0;que[hd]=S;tl++;
  while(hd<tl){
    int x=que[hd];hd++;
    if(x==T)return 1;
    for(int i=head[x];i;i=nxt[i]){
      int to=t[i],f=w[i];
      if(f>0&&dis[to]==-1){
	    dis[to]=dis[x]+1;
	    que[tl++]=to;
      }
    }
  }
  return 0;
}

il int dfs(int x,int flll){
  if(x==T)return flll;
  int tag=0;
  for(int i=head[x];i;i=nxt[i]){
    int to=t[i],f=w[i];
    if(dis[to]==dis[x]+1&&f>0){
      f=dfs(to,min(flll-tag,f));
      tag+=f;
      w[i]-=f;w[i^1]+=f;
      if(tag==flll)return tag;
    }
  }
  if(tag==0)dis[x]=-1;
  return tag;
}

il void dinic(){
  while(bfs())all-=dfs(S,inf);
  printf("%d\n",all);
}

int main(){
  init();
  dinic();
  return 0;
}

附带相关格式样例

输入格式:

第一行两个整数,n 和 m,分别表示工作数和机器数.

接下来输入分为 n 段,即对于每项工作:

第一行为两个整数,a 和 b,分别为完成该工作的收益和工序数;

接下来 b 行,每行两个整数,x 和 y,分别表示完成该工序需要的机器和机器的租赁费用.

接下来一行有 m 个数, wi 表示购买每台机器的费用.

输出格式:

输出仅一行,即可以获得的最大收益.

输入样例:

5 5
1 3
2 3
3 2
5 5
1 1
2 2
4 1
5 2
4 4
1 4
2 3
3 3
4 2
5 5
1 5
2 3
3 3
4 1
5 5
1 1 1 4 4

输出样例:

5

 

posted @ 2017-07-30 12:30  穆忞千载  阅读(254)  评论(4编辑  收藏  举报