[最大费用可行流 || 单纯形] BZOJ 3118 Orz the MST

首先很容易根据树边非树边的大小关系列出线性关系

然后对偶一下

可以用线性规划

也可以跑费用流

把对偶后的线性约束写出来 建图就不难看懂了


#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;
  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]); read(sg[i]); read(ia); read(ib);
    if (sg[i]){
      add(sx[i],sy[i],i,++inum);
      add(sy[i],sx[i],i,++inum);
      val[i]=ib;
      MCMF::link(MCMF::S,i,0,val[i]);
    }else{
      val[i]=ia;
      MCMF::link(i,MCMF::T,0,val[i]);
    }
  }
  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、付费专栏及课程。

余额充值