[费用流] POJ 3680 Intervals

时间:2021-12-10 16:25:14

简单的费用流建模 一个区间ab 从a到b连边 然后从源到汇一路串起来 源汇容量K

解题报告 之 POJ3680 Intervals

我们注意到图中的节点连接都是一路向右的,所以这k的流量经过所有节点最多1次,所以不会有节点被访问超过k次。

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

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,f,w;
  int next;
}G[N<<1];
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 pre[N],dis[N],ins[N];
int Q[1000005],l,r;

#define V G[p].v

ll Maxcost;
inline bool SPFA(){
  for (int i=1;i<=T;i++) dis[i]=-1<<30,pre[i]=0,ins[i]=0;
  l=r=-1; dis[S]=0; Q[++r]=S; ins[S]=1;
  while (l!=r){
    int u=Q[++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[++r]=V,ins[V]=1;
      }
  }
  if (dis[T]<0) return 0;
  int minv=1<<30;
  for (int p=pre[T];p;p=pre[G[p].u])
    minv=min(minv,G[p].f);
  Maxcost+=(ll)minv*dis[T];
  for (int p=pre[T];p;p=pre[G[p].u])
    G[p].f-=minv,G[p^1].f+=minv;
  return 1;
}

int sx[N],icnt;
inline int Bin(int x){
  return lower_bound(sx+1,sx+icnt+1,x)-sx;
}

int n,K;
int us[N],vs[N],ws[N];

int main(){
  int Q;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(Q);
  while (Q--){
    icnt=0;
    read(n); read(K);
    for (int i=1;i<=n;i++)
      read(us[i]),read(vs[i]),read(ws[i]),sx[++icnt]=us[i],sx[++icnt]=vs[i];
    sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1;
    S=icnt+1+1,T=icnt+1+2;
    for (int i=1;i<=n;i++)
      us[i]=Bin(us[i]),vs[i]=Bin(vs[i]),link(us[i],vs[i],ws[i],1);
    for (int i=1;i<=icnt;i++) link(i,i+1,0,1<<30);
    link(S,1,0,K); link(icnt+1,T,0,K);
    Maxcost=0; while (SPFA());
    printf("%lld\n",Maxcost);
    cl(head); inum=1;
  }
  return 0;
}