zoukankan      html  css  js  c++  java
  • 【TJOI2014】匹配

    题面

    https://www.luogu.org/problem/P3967

    题解

    二分图上求可能/必然割边,由于当时还非常弱,不会用$tarjan$,所以是把边删去重跑一次的。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #include<cassert>
    #include<queue>
    #define ri register int
    #define N 500
    #define INF 1000000007
    using namespace std;
    int n;
    vector<int> id[N*5];
    int w[2*N*N+4*N],tw[2*N*N+4*N],c[2*N*N+4*N],to[2*N*N+4*N],dis[N*5];
    int start[2*N*N+4*N];
    bool check[2*N*N+4*N];
    int used[N*5];
    
    int ans=0,cnt=-1;
    bool vis[N*5];
    int fro[N*5],cut[N*5],tot=0,con=0;
    
    struct node {
      int a,b;
      bool operator < (const node &rhs) const {
        return a<rhs.a;
      }
    } sy[N*5];
    
    void addedge(int u,int v,int co,int wo) {
      ++cnt; id[u].push_back(cnt); c[cnt]=co;  tw[cnt]=wo; to[cnt]=v; start[cnt]=u;
      ++cnt; id[v].push_back(cnt); c[cnt]=-co; tw[cnt]=0;  to[cnt]=u; start[cnt]=v;
    }
    queue<int> q;
    
    bool spfa() {
      memset(vis,0,sizeof(vis));
      for (ri i=0;i<=2*n;i++) dis[i]=-INF;
      dis[(2*n+1)]=0;
      while (!q.empty()) q.pop();
      q.push((2*n+1)); 
      vis[(2*n+1)]=1;
      while (!q.empty()) {
        int x=q.front(); q.pop(); vis[x]=0;
        for (ri i=0;i<id[x].size();i++) {
          int e=id[x][i];
          if (w[1^e] && dis[to[e]]<dis[x]-c[e]) {
            dis[to[e]]=dis[x]-c[e];
            if (!vis[to[e]]) vis[to[e]]=1,q.push(to[e]);
          }
        }
      }
      return dis[0]>-INF;
    }
    
    int dfs(int x,int limit) {
      vis[x]=1;
      if (x==(2*n+1)||(!limit)) return limit;
      int get=0;
      for (ri i=used[x];i<id[x].size();i++) {
        int e=id[x][i];
        if (dis[x]-c[e]==dis[to[e]] && !vis[to[e]] && w[e]) {
          int t=dfs(to[e],min(limit,w[e]));
          if (!t) continue;
          get+=t;limit-=t;
          w[e]-=t,w[1^e]+=t;
          used[x]=i;
          if (!limit) return get;
        }
      }
      return get;
    }
    
    void init() {
      for (ri i=0;i<=cnt;i++) w[i]=tw[i];
    }
    
    void zkw(int opt) {
      while(spfa()) {
        vis[(2*n+1)]=1;
        while (vis[(2*n+1)]) {
          memset(vis,0,sizeof(vis));
          memset(used,0,sizeof(used));
          if (opt) ans+=dfs(0,INF)*dis[0];
          else con+=dfs(0,INF)*dis[0];
        }
      }
    }
    
    int main() {
      scanf("%d",&n);
      for (ri i=1;i<=n;i++) {
        for (ri j=1;j<=n;j++) {
          int co;
          scanf("%d",&co);
          addedge(i,n+j,co,1);
        }
      }
      for (ri i=1;i<=n;i++) addedge(0,i,0,1);
      for (ri i=n+1;i<=2*n;i++) addedge(i,(2*n+1),0,1);
      init();zkw(1);
      printf("%d
    ",ans);
      int cc=0;
      for (ri i=0;i<=cnt;i+=2) {
        if (!w[i] && start[i]>=1 && start[i]<=n && to[i]>=n+1 && to[i]<=2*n) check[i]=1;
      }
      for (ri i=0;i<=cnt;i+=2) if (check[i]) {
        init();
        w[i]=0; w[1^i]=0;
        con=0;
        zkw(0);
        //printf("%d
    ",con);
        if (con!=ans) {
          sy[++cc]=(node){start[i],to[i]};
        }
      }
      sort(sy+1,sy+cc+1);
      for (ri i=1;i<=cc;i++) printf("%d %d
    ",sy[i].a,sy[i].b-n);
    }
  • 相关阅读:
    win7(64)未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序的解决办法
    很方便的工具——代码生成工具之Winform查询列表界面生成
    程序员十几个常用网站
    优秀程序员不得不知道的20个位运算技巧
    unset()索引数组
    git 撤销修改
    git 版本回退
    git 命令详解
    git多账户配置
    Git的.ssh文件夹的内容
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11426780.html
Copyright © 2011-2022 走看看