【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\n",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\n",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\n",sy[i].a,sy[i].b-n);
}

 

posted @ 2019-08-28 21:58  HellPix  阅读(201)  评论(0编辑  收藏  举报