[Floyd 一般图最小权完美匹配] 算法马拉松25 F River?Rever!

来源:互联网 发布:什么是少儿编程 编辑:程序博客网 时间:2024/05/17 06:31

首先把一个区间翻转的最小代价肯定不是题目给出的那个代价
我们先跑一通floyd就能搞出来最小代价
然后呢 把所有奇偶性变化的位置 连成一个完全图 跑最小权完美匹配就好了
不会带花树 拷了个随机匹配的板子

#include<bits/stdc++.h>using namespace std;typedef long long ll;namespace Work{  const ll OO=1LL<<40;  const int MAXN=405;  ll w[MAXN][MAXN], g[MAXN][MAXN];  int match[MAXN], path[MAXN], p[MAXN], len;  ll d[MAXN];  bool v[MAXN];  int n, m, k;  bool dfs(int i) {    path[len++] = i;    if (v[i]) return true;    v[i] = true;    for (int j = 0; j < k; ++j) {      if (i != j && match[i] != j && !v[j]) {    int kok = match[j];    if (d[kok] < d[i] + w[i][j] - w[j][kok]) {      d[kok] = d[i] + w[i][j] - w[j][kok];      if (dfs(kok)) return true;    }      }    }    --len;    v[i] = false;    return false;  }  ll solve() {    if (k&1)       return -1;    for (int i = 0; i < k; ++i) p[i] = i, match[i] = i ^ 1;    int cnt = 0;    for (;;) {      len = 0;      bool flag = false;      memset(d, 0, sizeof(d));      memset(v, 0, sizeof(v));      for (int i = 0; i < k; ++i) {    if (dfs(p[i])) {      flag = true;      int t = match[path[len - 1]], j = len - 2;      while (path[j] != path[len - 1]) {        match[t] = path[j];        swap(t, match[path[j]]);        --j;      }      match[t] = path[j];      match[path[j]] = t;      break;    }      }      if (!flag) {    if (++cnt >= 3) break;    random_shuffle(p, p+k);      }    }    ll ans = 0;    for (int i = 0; i < k; ++i) {      ll t = w[i][match[i]];      //    cout << t << endl;      if (t == 0) {    return -1;      }      ans += OO - t;    }    return ans/2;  }}#define read(x) scanf("%d",&(x))const int N=405;int n,w[N][N];char s[N],t[N];int a[N];int pos[N],pnt;int main(){  int x;  read(n); scanf("%s",s+1); scanf("%s",t+1);  for (int i=1;i<=n;i++)    for (int j=i;j<=n;j++)      read(x),w[i-1][j]=w[j][i-1]=x;  for (int k=0;k<=n;k++)    for (int i=0;i<=n;i++)      for (int j=0;j<=n;j++)    w[i][j]=min(w[i][j],w[i][k]+w[k][j]);  for (int i=1;i<=n;i++) a[i]=s[i]^t[i];  for (int i=1;i<=n;)    if (a[i]){      int j=i;      while (j+1<=n && a[j+1]) j++;      pos[++pnt]=i-1,pos[++pnt]=j;      i=j+1;    }else      i++;  Work::k=pnt;  for (int i=1;i<=pnt;i++)    for (int j=1;j<=pnt;j++)      Work::w[i-1][j-1]=Work::OO-w[pos[i]][pos[j]];  ll ans=Work::solve();  printf("%lld\n",ans);  return 0;}
阅读全文
0 0
原创粉丝点击