1. 程式人生 > >FZU2295 Human life:網絡流-最大權閉合子圖-二進制優化-第九屆福建省大學生程序設計競賽

FZU2295 Human life:網絡流-最大權閉合子圖-二進制優化-第九屆福建省大學生程序設計競賽

man scrip blog memset return pac dinic type bool

目錄

  • Catalog
  • Solution:

(有任何問題歡迎留言或私聊 && 歡迎交流討論哦

Catalog

Problem:Portal傳送門

?原題目描述在最下面。
?題意就是很裸的最大權閉合子圖。
?推薦閱讀:胡伯濤《最小割模型在信息學競賽中的應用》
?完完全全的模板題:新疆大學五月月賽-D-勤奮的楊老師
?本題題意:m(50)個任務,n個技能。完成每個任務由相應的收益,完成每個任務前必須學一些技能。有些技能由先修技能。
?有些任務不能同時完成。

Solution:

?訓練賽的時候聽隊友講完題意,一眼就直接建對圖了,但是沒敢敲,因為比賽剛開始,想先寫簽到題。
?詳細de題解啊啊啊

?直接講建圖:源點S想每個任務連邊,流量為其收益,每個任務向其需要的技能連邊,每個任務向先修技能連邊,每個技能向匯點T連邊,流量為其花費。答案是\(sum_{任務}-maxflow\).
?難點在於有些任務不能同時完成。因為只有k(5)對,直接二進制枚舉所有對互斥情況。為1則不能選第一個任務,為0則不能選第二個任務。不選就是取反再異或一下。
?細節看代碼吧。

AC_Code:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define mme(a,b) memset((a),(b),sizeof((a)))  
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;

const int MXN = 2e2+7;
const int MXE = MXN*MXN;
struct DINIC{
  int tot,vt,vs;
  int d[MXN],head[MXN];
  struct lp{
    int v,w,nex;
  }cw[MXE];
  void add_edge(int a,int b,int c){
    cw[++tot].v=b;cw[tot].nex=head[a],cw[tot].w=c;
    head[a]=tot;
    cw[++tot].v=a;cw[tot].nex=head[b],cw[tot].w=0;
    head[b]=tot;
  }
  bool bfs(){
    memset(d,-1,sizeof(d));
    queue<int>Q;
    Q.push(vt);d[vt]=0;
    while(!Q.empty()){
      int u=Q.front();
      Q.pop();
      for(int i=head[u];i!=-1;i=cw[i].nex){
        int v=cw[i].v;
        if(cw[i^1].w&&d[v]==-1){
          d[v]=d[u]+1;
          Q.push(v);
        }
      }
    }
    return d[vs]!=-1;
  }
  int dfs(int x,int f){
    if(x==vt||f==0) return f;
    int use=0,w;
    for(int i=head[x];i!=-1;i=cw[i].nex){
      int to=cw[i].v;
      if(d[to]==d[x]-1 && cw[i].w){
        w=dfs(to,min(cw[i].w,f-use));
        cw[i].w-=w,cw[i^1].w+=w;
        use+=w;
        if(use==f) return f;
      }
    }
    return use;
  }
  void init(int st,int ed){
    tot = -1;
    memset(head,-1,sizeof(head));
    vs = st; vt = ed;
  }
  int max_flow(){
    int ans=0;
    while(bfs())ans+=dfs(vs,INF);
    return ans;
  }
}dinic;
const int N = 105;
int n, m, k;
int vs, vt;
struct lp{
  int v,x;
  int a[N];
}ar[N],br[N];
int c[N],d[N];
int main(){
  int tim;
  scanf("%d", &tim);
  while(tim--){
    scanf("%d%d%d", &n, &m, &k);
    vs = 0;vt = m+n+1;
    for(int i = 1; i <= n; ++i){
      int v,x;
      scanf("%d%d", &v, &x);
      ar[i].v=v;ar[i].x=x;
      for(int j = 0; j < x; ++j){
        scanf("%d", &ar[i].a[j]);
      }
    }
    for(int i = 1; i <= m; ++i){
      int v,x;
      scanf("%d%d", &v, &x);
      br[i].v=v;br[i].x=x;
      for(int j = 0; j < x; ++j){
        scanf("%d", &br[i].a[j]);
      }
    }
    for(int i = 0; i < k; ++i){
      scanf("%d%d", &c[i], &d[i]);
      --c[i];--d[i];
    }
    int sta = 1 << k, ans = 0;
    //printf("%lld\n", 1<<50);
    for(int t = 0; t < sta; ++t){
      LL hhh = (1LL<<m)-1;
      for(int i = 0; i < k; ++i){
        LL x = 1LL<<c[i], y = 1LL<<d[i];
        if(t&(1<<i)){
          hhh &= (~x);
        }else{
          hhh &= (~y);
        }
      }
      //printf("hhh = %d\n", hhh);
      dinic.init(vs, vt);
      for(int i = 1, v; i <= n; ++i){
        dinic.add_edge(i+m,vt,ar[i].v);
        for(int j = 0; j < ar[i].x; ++j){
          v = ar[i].a[j];
          dinic.add_edge(i+m,v+m,INF);
        }
      }
      int sum = 0, tmp;
      for(int i = 1, v; i <= m; ++i){
        if((hhh&(1LL<<(i-1)))==0)continue;
        dinic.add_edge(vs,i,br[i].v);
        sum += br[i].v;
        for(int j = 0; j < br[i].x; ++j){
          v = br[i].a[j];
          dinic.add_edge(i,v+m,INF);
        }
      }
      tmp = dinic.max_flow();
      ans = max(ans, sum - tmp);
    }
    printf("%d\n", ans);
  }
  return 0;
}


Problem Description:

技術分享圖片

FZU2295 Human life:網絡流-最大權閉合子圖-二進制優化-第九屆福建省大學生程序設計競賽