[对偶 KM算法 生成树 || 最大费用可行流 || 线性规划] BZOJ 1937 [Shoi2004]Mst 最小生成树

44 篇文章 0 订阅
34 篇文章 0 订阅

树边减,非树边加,wi表示i号边原来的边权,di表示i号边的改变量

对于一条非树边,覆盖所有树边,都要满足:wi−di≤wj+dj

得wi−wj≤di+dj

这样的话d就是KM算法里的顶标 对偶成最大权匹配

跑最大匹配即可


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;

inline char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
    return *p1++;
}

inline void read(int &x)
{
    char c=nc(),b=1;
    for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
    for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

namespace KMA{
    const int N=805;
    int n,m,w[N][N];
    int mate[N],S[N],T[N],lx[N],ly[N],sla[N];
    bool match(int u)
    {
        S[u]=1;
        for (int v=1;v<=m;v++)
        {
            if (T[v]) continue;
            if (lx[u]+ly[v]==w[u][v])
            {
                T[v]=1;
                if (!mate[v] || match(mate[v]))
                    return mate[v]=u,1;
            }else
                sla[v]=min(sla[v],lx[u]+ly[v]-w[u][v]);
        }
        return 0;
    }
    int KM()
    {
        if (n>m)
        {
            for (int i=1;i<=n;i++)
                for (int j=1;j<=i && j<=m;j++)
                    swap(w[i][j],w[j][i]);
            swap(n,m);
        }
        cl(mate); cl(ly);
        for (int i=1;i<=n;i++)
        {
            lx[i]=-1<<30;
            for (int j=1;j<=m;j++) lx[i]=max(lx[i],w[i][j]);
        }
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++) sla[j]=1<<30;
            for (;;)
            {
                cl(S); cl(T);
                if (match(i)) break;
                int a=1<<30;
                for (int j=1;j<=m;j++) if (!T[j]) a=min(a,sla[j]);
                for (int j=1;j<=n;j++) if (S[j]) lx[j]-=a;
                for (int j=1;j<=m;j++) if (T[j]) ly[j]+=a; else sla[j]-=a;
            }
        }
        int ret=0;
        for (int i=1;i<=m;i++)
            ret+=w[mate[i]][i];
        return ret;
    }
}

const int N=55,K=10,M=805;

struct edge{
    int u,v,w,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int w,int p){
    G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}

int n,m;
int ln,rn;
int fat[N][K],depth[N],idx[N],wgt[N];

#define V G[p].v
inline void dfs(int u,int fa)
{
    fat[u][0]=fa; depth[u]=depth[fa]+1;
    for (int k=1;k<K;k++) fat[u][k]=fat[fat[u][k-1]][k-1];
    for (int p=head[u];p;p=G[p].next)
        if (V!=fa)
            idx[V]=++rn,wgt[V]=G[p].w,dfs(V,u);
}

inline int LCA(int u,int v){
    if (depth[u]<depth[v]) swap(u,v);
    for (int k=K-1;~k;k--)
        if ((depth[u]-depth[v])&(1<<k))
            u=fat[u][k];
    if (u==v) return u;
    for (int k=K-1;~k;k--)
        if (fat[u][k]!=fat[v][k])
            u=fat[u][k],v=fat[v][k];
    return fat[v][0];
}

struct edges{
    int u,v,w,f;
}E[M];

inline void build(int u,int lca,int id,int w)
{
    if (u==lca) return;
    KMA::w[id][idx[u]]=max(0,wgt[u]-w);
    build(fat[u][0],lca,id,w);
}

int main()
{
    int iu,iv,iw,lca;
    freopen("t.in","r",stdin);
    freopen("t.out","w",stdout);
    read(n); read(m);
    for (int i=1;i<=m;i++)
        read(E[i].u),read(E[i].v),read(E[i].w);
    for (int i=1;i<n;i++)
    {
        read(iu); read(iv);
        for (int j=1;j<=m;j++)
            if ((E[j].u==iu && E[j].v==iv) || (E[j].u==iv && E[j].v==iu))
                E[j].f=1,iw=E[j].w;
        add(iu,iv,iw,++inum); add(iv,iu,iw,++inum);
    }
    dfs(1,0);
    for (int i=1;i<=m;i++)
        if (!E[i].f)
        {
            iu=E[i].u; iv=E[i].v;
            lca=LCA(iu,iv);
            build(iu,lca,++ln,E[i].w);
            build(iv,lca,ln,E[i].w);
        }
    KMA::n=ln; KMA::m=rn;
    printf("%d\n",KMA::KM());
    return 0;
}

费用流的做法:http://blog.csdn.net/u014609452/article/details/52598726


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2){ p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=1005;

struct edge{
  int u,v,next; int idx;
}G[N<<1];
int head[N],inum;

inline void add(int u,int v,int idx,int p){
  G[p].u=u; G[p].v=v; G[p].idx=idx; G[p].next=head[u]; head[u]=p;
}

int n,m;
const int K=21;

int fat[N][K],depth[N],fad[N];
#define V G[p].v
inline void dfs(int u,int fa){
  fat[u][0]=fa; depth[u]=depth[fa]+1;  
  for (int k=1;k<K;k++) fat[u][k]=fat[fat[u][k-1]][k-1];  
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa)
      dfs(V,u),fad[V]=G[p].idx;
}

inline int LCA(int u,int v){  
  if (depth[u]<depth[v]) swap(u,v);  
  for (int k=K-1;~k;k--)  
    if ((depth[u]-depth[v])&(1<<k))  
      u=fat[u][k];  
  if (u==v) return u;  
  for (int k=K-1;~k;k--)  
    if (fat[u][k]!=fat[v][k])  
      u=fat[u][k],v=fat[v][k];  
  return fat[v][0];  
}  

namespace MCMF{
  const int N=1005;  
  struct edge{  
    int u,v,w,f,next;  
  }G[1000005];  
  int head[N],inum=1;  
  inline void add(int u,int v,int w,int f,int p){  
    G[p].u=u; G[p].v=v; G[p].w=w; G[p].f=f; G[p].next=head[u]; head[u]=p;  
  }  
  inline void link(int u,int v,int w,int f){  
    add(u,v,w,f,++inum); add(v,u,-w,0,++inum);  
  } 
  int S,T;  
  int dis[N],ins[N],pre[N];  
  const int NQ=1000005;
#define ad(x) ((x)+1==NQ?(x)=0:++(x)) 
  int Q[NQ],l,r;  
  int Maxcost;
  inline bool SPFA(){  
    for (int i=1;i<=T;i++) dis[i]=-1<<30,ins[i]=0,pre[i]=0;  
    l=-1,r=-1;  
    Q[ad(r)]=S; dis[S]=0; ins[S]=1;  
    while (l!=r){  
      int u=Q[ad(l)]; ins[u]=0;  
      for (int p=head[u];p;p=G[p].next)  
	if (G[p].f && dis[V]<dis[u]+G[p].w){  
	  dis[V]=dis[u]+G[p].w; pre[V]=p;  
	  if (!ins[V]) Q[ad(r)]=V,ins[V]=1;  
	}  
    }  
    if (dis[T]<=0) return false;  
    int minimum=1<<30;  
    for (int p=pre[T];p;p=pre[G[p].u])  
      minimum=min(minimum,G[p].f);  
    for (int p=pre[T];p;p=pre[G[p].u]){  
      G[p].f-=minimum; G[p^1].f+=minimum;  
      Maxcost+=minimum*G[p].w;  
    }  
    return true;  
  }
  inline void Solve(){
    while (SPFA());
  }
}

int cnt;
int sx[N],sy[N],sw[N],sg[N],val[N];

int main(){
  int ia,ib,iu,iv;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m);
  MCMF::S=m+1; MCMF::T=m+2;
  for (int i=1;i<=m;i++){
    read(sx[i]); read(sy[i]); read(sw[i]);
    val[i]=1;
  }
  for (int i=1;i<n;i++){
    read(iu),read(iv);
    for (int j=1;j<=m;j++)
      if ((iu==sx[j]&&iv==sy[j]) || (iu==sy[j]&&iv==sx[j]))
	sg[j]=1;
  }
  for (int i=1;i<=m;i++){
    if (sg[i])
      MCMF::link(MCMF::S,i,0,val[i]);
    else
      MCMF::link(i,MCMF::T,0,val[i]);
    if (sg[i]){
      add(sx[i],sy[i],i,++inum);
      add(sy[i],sx[i],i,++inum);
    }
  }
  dfs(1,0);
  for (int i=1;i<=m;i++)
    if (!sg[i]){
      int u=sx[i],v=sy[i],lca=LCA(u,v);
      while (u!=lca){
	if (sw[fad[u]]>sw[i])
	  MCMF::link(fad[u],i,sw[fad[u]]-sw[i],1<<30);
	u=fat[u][0];
      }
      while (v!=lca){
	if (sw[fad[v]]>sw[i])
	  MCMF::link(fad[v],i,sw[fad[v]]-sw[i],1<<30);
	v=fat[v][0];
      }
    }
  MCMF::Solve();
  printf("%d\n",MCMF::Maxcost);
  return 0;
}



还有线性规划的做法


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值