网络流24题 部分总结

网络流24题 部分总结

慢慢写吧。。。

以前做过一些了;

然后发现也做了不少了,集中写一下。

警告:

  1. 题目按照随机顺序排列。

  2. 文章中只有建模的方法。

最小路径覆盖问题

http://cogs.pro:8080/cogs/problem/problem.php?pid=728

题目即题解。。。

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define File
#define Fname "path3"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define t (dis[i])
typedef long long ll;
il int gi(){
    rg int x=0;rg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}
const int maxn=151<<1,maxm=6002;
int id=0,fir[maxn],dis[maxm],nxt[maxm];
il vd add(int a,int b){
    nxt[++id]=fir[a],fir[a]=id,dis[id]=b;
}
bool vis[maxn];int match[maxn],in[maxn],to[maxn];
il bool dfs(int now){
    erep(i,now)
	if(!vis[t]){
	    vis[t]=1;
	    if(match[t]==-1||dfs(match[t])){match[t]=now;return 1;}
	}
    return 0;
}
int main(){
    freopen(Fname".in","r",stdin);
    freopen(Fname".out","w",stdout);
    rg int n=gi(),m=gi();
    while(m--){rg int i=gi(),j=gi();add(i,j+n);}
    memset(match,-1,sizeof match);
    int ans=0;
    drep(i,n,1){
	memset(vis,0,sizeof vis);
	vis[i]=1;if(dfs(i))++ans;
    }
    drep(i,n+n,n+1)if(match[i]+1)to[match[i]]=i-n,in[i-n]=1;
    rep(i,1,n)if(!in[i]){
	int now=i;printf("%d ",now);
	while(to[now])now=to[now],printf("%d ",now);
	puts("");
    }
    printf("%d
",n-ans);
    return 0;
}

魔术球问题

http://cogs.pro:8080/cogs/problem/problem.php?pid=396

我会打表!

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,ans[]={233333,1,3,7,11,17,23,31,39,49,59,71,83,97,111,127,143,161,179,199,219,241,263,287,311,337,363,391,419,449,479,511,543,577,611,647,683,721,759,799,839,881,923,967,1011,1057,1103,1151,1199,1249,1299,1351,1403,1457,1511,1567,1623,1681,1739,1799,1859};
int main() {
freopen("balla.in","r",stdin);
freopen("balla.out","w",stdout);
	scanf("%d",&n);
	printf("%d",ans[n]);
	return 0;
}

正解是累加答案然后连边增广。不知道这是不是我当年写的了。丑的一批。唉。

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#define re register
#define inf 1<<29
#define il inline
#define rep(i,a,b) for(register int i=a;i<=b;++i)
#define file(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
const int N=1610;
struct Edge{
  int to,net,flow,cap;
  int fr;
}e[N*N];
int head[N*2],num_e,n,m;
il void add(int x,int y,int c){
  e[++num_e].to=y,e[num_e].cap=c,e[num_e].net=head[x],head[x]=num_e;
  e[num_e].fr=x;
}
const int oh=1604;
int s,t;
inline int gi() {
  re int res=0,f=1;re char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  if(ch=='-')f=-1,ch=getchar();while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();return res*f;
}
int lev[N*2];
il bool bfs(){
  queue<int> q;
  memset(lev,0,sizeof(lev));
  q.push(s);lev[s]=1;re int u;
  while(!q.empty()){
    u=q.front();q.pop();
    for(int i=head[u];i!=-1;i=e[i].net){
      int to=e[i].to;
      if(!lev[to]&&e[i].cap>e[i].flow){
        lev[to]=lev[u]+1;
        q.push(to);
        if(lev[t]) return true;
      }
    }
  }
  return false;
}
int dfs(int x,int f){
  if(x==t) return f;
  int tag=0;
  for(int i=head[x];i!=-1;i=e[i].net){
    int to=e[i].to;
    if(lev[to]==lev[x]+1&&e[i].cap>e[i].flow){
      int c=dfs(to,min(e[i].cap-e[i].flow,f-tag));
      e[i].flow+=c;
      e[i^1].flow-=c;
      tag+=c;
      if(tag==f) break;
    }
  }
  if(!tag) lev[x]=0;
  return tag;
}
int Dinic(){
  re int flow=0;
  while(bfs())
    flow+=dfs(s,inf);
  return flow;
}
bool pd[N*2];
int nxt[N*2];
void get_ans(int n){
  for(re int i=0;i<=num_e;i+=2) {
    if(e[i].fr==s||e[i].to==t||e[i].cap!=e[i].flow) continue;
    nxt[e[i].fr]=e[i].to-oh;
    pd[e[i].to-oh]=1;
  }
  for(re int i=1;i<=n;i++)
    if(!pd[i]){
      re int u=i;
      printf("%d ",u);
      while(nxt[u]) u=nxt[u],printf("%d ",u);
      puts("");
    }
}
void init(){
  e[num_e-1].cap=0,e[num_e].cap=0;
  rep(i,0,num_e) e[i].flow=0;
  Dinic();
}
int main(){
  memset(head,-1,sizeof(head));num_e=-1;
  s=0,t=3210;
  re int i=0;
  m=gi();
  int f=0;
  for(;;){
    i++;
    rep(j,1,i-1) if((int)sqrt(i+j)*(int)sqrt(i+j)==i+j) add(j,i+oh,1),add(i+oh,j,0);
    add(s,i,1),add(i,s,0);
    add(i+oh,t,1),add(t,i+oh,0);
    f+=Dinic();
    if(i-f>m) break;
  }
  printf("%d
",i-1);
  return 0;
}

搭配飞行员

http://cogs.pro:8080/cogs/problem/problem.php?pid=14

记得是我第一次写匈牙利把。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define t (dis[i])
using namespace std;
const int maxn=110,maxm=510<<1;
void init();
void work();
bool dfs(int);
int main() {
	init(),work();
	return 0;
}
inline int gi();
int n,n1,m,fir[maxn],nxt[maxm],dis[maxm];
inline void adde(int a,int b,int id) {
	nxt[id]=fir[a],fir[a]=id,dis[id]=b;
}
bool vis[maxn];
int T[maxn];
void work() {
	memset(T,-1,sizeof(T));
	int ans=0;
	for(int i=1; i<=n1; i++) {
		memset(vis,0,sizeof(vis));
		ans+=dfs(i);
	}
	printf("%d
",ans);
}
void init() {
	scanf("%d%d",&n,&n1);
	int a,b;
	while(scanf("%d%d",&a,&b)==2)adde(a,b,++m),adde(b,a,++m);
}
bool dfs(int now) {
	for(int i=fir[now]; i; i=nxt[i])
		if(!vis[t]) {
			vis[t]=1;
			if(T[t]==-1||dfs(T[t])){
				T[t]=now;return 1;
			}
		}
	return 0;
}

骑士共存

http://cogs.pro:8080/cogs/problem/problem.php?pid=746

你看他都帮你涂好颜色了

能互相攻击就连边,显然二分图,n*m-匹配=答案

#include<cstdio>
#include<algorithm>
#include<cstring>
#define check(x,y) (x>0&&x<=n&&y>0&&y<=n)
using namespace std;
const int X[]= {99999,-1,1,2,2};
const int Y[]= {888888888,2,2,1,-1};
int id[201][201],fir[40001],nxt[40001*8*2],dis[40001*8*2];
inline int gi() {
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*f;
}
int iiddd=0;
inline void adde(int a,int b) {
	nxt[++iiddd]=fir[a],fir[a]=iiddd,dis[iiddd]=b;
}
int N=0,n,m;
inline void init() {
	int a,b;
	n=gi(),m=gi();
	for(int i=1; i<=m; i++)a=gi(),b=gi(),id[a][b]=-1;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
			if(id[i][j]!=-1)id[i][j]=++N;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)if(id[i][j]>0)
			for(int k=1; k<5; k++)
				if(check((i+X[k]),(j+Y[k]))&&id[i+X[k]][j+Y[k]]>0) {
					adde(id[i][j],id[i+X[k]][j+Y[k]]);
					adde(id[i+X[k]][j+Y[k]],id[i][j]);
				}
}
int match[40001],vis[40001];
inline bool dfs(int now) {
	for(int i=fir[now]; i; i=nxt[i])
		if(!vis[dis[i]]) {
			int t=dis[i];
			vis[t]=1;
			if(match[t]==-1||dfs(match[t])) {
				match[t]=now;
				return 1;
			}
		}
	return 0;
}
inline void hun() {
	int ans=0;
	memset(match,-1,sizeof match);
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
			if((i+j)&1) {
				memset(vis,0,sizeof vis);
				ans+=dfs(id[i][j]);
			}
	printf("%d",N-ans);
}
int main() {
	init(),hun();
	return 0;
}

我以前代码写的好丑啊

最长递增子序列

http://cogs.pro:8080/cogs/problem/problem.php?pid=731

  1. 动态规划秒之。
  2. i向满足(j>i且x_j>x_i)的j连边;
    (f_i=s),就i向T连边;
    S向每个点连边。
    权值均为1。
  3. 同2
    S向1连的边权值改为inf;
    若n向T有连边,权值改为inf。
  4. 有个坑点,这是最长不下降子序列。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define t (dis[i])
using namespace std;
inline int gi() {
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*f;
}
inline void Dp();
inline void solve(int);
int X[501],F[501];
int n,K,S,T;
int main() {
	n=gi();
	for(int i=1; i<=n; i++)X[i]=gi();
	Dp();
	S=n+1,T=n+2,solve(1),solve(1000);
	return 0;
}
const int maxn=521,maxm=400001<<1;
int fir[maxn],dis[maxm],w[maxm],nxt[maxm],dep[maxn];
inline void Dp() {
	int ans=0;
	for(int i=1; i<=n; i++) {
		F[i]=1;
		for(int j=1; j<i; j++)if(X[j]<=X[i])F[i]=max(F[i],F[j]+1);
		ans=max(F[i],ans);
	}
	printf("%d
",K=ans);
}
int Index=1;
inline void adde(int a,int b,int ww) {
	nxt[++Index]=fir[a],fir[a]=Index,dis[Index]=b,w[Index]=ww;
	if(ww)adde(b,a,0);
}
inline bool BFS() {
	queue<int>bfs;
	memset(dep,0,sizeof dep);
	bfs.push(S);
	bool yes[600]= {0};
	yes[S]=1,dep[S]=0;
	while(!bfs.empty()) {
		int now=bfs.front();
		for(int i=fir[now]; i; i=nxt[i])
			if(w[i]>0&&!yes[t])
				yes[t]=1,bfs.push(t),dep[t]=dep[now]+1;
		bfs.pop();
	}
	return yes[T];
}
inline int Dinic(int now,int h) {
	if(now==T)return h;
	int ans=0;
	for(int i=fir[now]; i; i=nxt[i])
		if(w[i]>0&&dep[t]==dep[now]+1) {
			int D=Dinic(t,min(h,w[i]));
			w[i]-=D,w[i^1]+=D,ans+=D,h-=D;
			if(h==0)return ans;
		}
	return ans;
}
inline void solve(int hehe) {
	memset(fir,0,sizeof fir);
	Index=1;
	for(int i=1; i<n; i++)
		for(int j=i+1; j<=n; j++)
			if(X[i]<=X[j]&&F[i]+1==F[j])adde(i,j,1);
	if(hehe^1) {
		adde(S,1,hehe);
		for(int i=2; i<=n; i++)if(F[i]==1)adde(S,i,1);
		for(int i=1; i<n; i++)if(F[i]==K)adde(i,T,1);
		if(F[n]==K)adde(n,T,hehe);
	} else {
		for(int i=1; i<=n; i++)if(F[i]==1)adde(S,i,1);
		for(int i=1; i<=n; i++)if(F[i]==K)adde(i,T,1);
	}
	int ans=0;
	while(BFS())ans+=Dinic(S,10000000);
	printf("%d
",ans);
}

方格取数问题

懒得放链接了。。

结论题。。

先染色,S向黑点连边,权值为这个数;白点向T点连边,权值为这个数。相邻的点连边,权值为inf。

总数字-最大流=答案。。。

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define t (dis[i])
typedef long long ll;
il int gi(){
    rg int x=0;rg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}
const int maxn=30*30+10,maxm=30*30*4+100,S=1,T=2;
int fir[maxn],nxt[maxm],dis[maxm],w[maxm],id=1;
int X[]={23333,0,0,1,-1},Y[]={23333,1,-1,0,0};
il vd add(int a,int b,int c){
    nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c;
    if(c)add(b,a,0);
}
int num[31][31];
bool vis[maxn];
il int ff(int now,int end,int minn){
    if(now==end)return minn;
    vis[now]=1;
    erep(i,now)
	if(!vis[dis[i]]&&w[i]){
	    rg int down=ff(dis[i],end,min(minn,w[i]));
	    if(down){w[i]-=down,w[i^1]+=down;return down;}
	}
    return 0;
}
int main(){
    int n=gi(),m=gi(),Id=2,sum=0,a=0;
    rep(i,1,n)rep(j,1,m){
	num[i][j]=++Id;
	sum+=a=gi();
	if((i+j)&1)add(S,num[i][j],a);
	else add(num[i][j],T,a);
    }
    rep(i,1,n)rep(j,1,m)if((i+j)&1)rep(k,1,4)
	if(num[i+X[k]][j+Y[k]])add(num[i][j],num[i+X[k]][j+Y[k]],666666666);
    int flow,Flow=0;
    while(flow=ff(S,T,666666666))Flow+=flow,memset(vis,0,sizeof vis);
    printf("%d
",sum-Flow);
    return 0;
}

汽车加油行驶

最短路乱入。。

设f(x,y,k)为走到点(x,y),且还能走k条边的最小费用。

依题意连边就好了。。。

好像n<=100(把)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 120
inline int read()
{
	int x=0,t=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=-1,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*t;
}
struct Line
{
	int v,next,w;
}e[MAX*MAX*MAX];
int h[MAX*MAX],cnt=1,tot;
int m[MAX*MAX],g[MAX][MAX],n,K,A,B,C;
bool vis[MAX*MAX][15];
inline void Add(int u,int v,int w)
{
	e[cnt]=(Line){v,h[u],w};h[u]=cnt++;
}
int dis[MAX*MAX][15];
void SPFA()
{
	memset(dis,63,sizeof(dis));
	dis[g[1][1]][K]=0;
	queue<int> Q,Q1;
	Q.push(g[1][1]);Q1.push(K);
	while(!Q.empty())
	{
		int u=Q.front(),t=Q1.front();
		Q.pop();Q1.pop();
		if(t!=0)
		{
			for(int i=h[u];i;i=e[i].next)
			{
				int v=e[i].v,gg=t-1,Dis=dis[u][t]+e[i].w;
				if(m[v])gg=K,Dis+=A;
				if(dis[v][gg]>Dis)
				{
					dis[v][gg]=Dis;
					if(!vis[v][gg])vis[v][gg]=true,Q.push(v),Q1.push(gg);
				}
			}
		}
		int v=u,gg=K,Dis=dis[u][t]+C+A;
		if(dis[v][gg]>Dis)
		{
			dis[v][gg]=Dis;
			if(!vis[v][gg])vis[v][gg]=true,Q.push(v),Q1.push(gg);
		}
		vis[u][t]=false;
	}
}
int main()
{
	n=read();K=read();A=read();B=read();C=read();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			g[i][j]=++tot,m[g[i][j]]=read();;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
		{
			if(i!=n)Add(g[i][j],g[i+1][j],0);
			if(j!=n)Add(g[i][j],g[i][j+1],0);
			if(i!=1)Add(g[i][j],g[i-1][j],B);
			if(j!=1)Add(g[i][j],g[i][j-1],B);
		}
	SPFA();
	int ans=1e9;
	for(int i=0;i<=K;++i)ans=min(ans,dis[g[n][n]][i]);
	printf("%d
",ans);
	return 0;
}

数字梯形

需要用到拆点的思想。。。

本来是每个点向下面两个点连边的,然而这样无法限制节点的流量,于是拆点

不想写了。。

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define inf 10000000
#define up +0
#define down +1
#define t (dis[i])
const int maxn=1001<<1,maxm=10000<<1,S=2000,T=2001;
using namespace std;
int fir[maxn],dis[maxm],w[maxm],cost[maxm],nxt[maxm],id=1,m,n;
int INDEX=0;
inline void add(int a,int b,int c,int d,int e=0){
  nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c,cost[id]=d;
  if(c)add(b,a,0,e);
}
int num[21][41],Index[21][41];
inline void build(int a,int b){
  memset(fir,0,sizeof fir);
  for(int i=1;i<=m;i++)add(S,Index[1][i]up,1,0);
  for(int i=1;i<=m+n-1;i++)add(Index[n][i]down,T,a,0);
  for(int i=1;i<n;i++)
    for(int j=1;j<m+i;j++){
      add(Index[i][j]up,Index[i][j]down,a,-num[i][j],num[i][j]);
      add(Index[i][j]down,Index[i+1][j]up,b,0);
      add(Index[i][j]down,Index[i+1][j+1]up,b,0);
    }
  for(int j=1;j<m+n;j++)
      add(Index[n][j]up,Index[n][j]down,a,-num[n][j],num[n][j]);
}
int que[maxn],vis[maxn],pre[maxn],Dis[maxn];
inline bool spfa(){
  int hd=1,tl=1;
  for(int i=1;i<=INDEX;i++)Dis[i]=inf;
  memset(vis,0,sizeof vis);
  Dis[T]=inf,Dis[S]=0,que[tl++]=S,vis[S]=1;
  while(hd^tl){
    int now=que[hd];
    for(int i=fir[now];i;i=nxt[i])
      if(w[i]>0&&Dis[t]>Dis[now]+cost[i]){
	Dis[t]=Dis[now]+cost[i],pre[t]=i;
	if(!vis[t])vis[t]=1,que[tl]=t,tl=(tl+1)%maxn;
      }
    vis[now]=0,hd=(hd+1)%maxn;
  }
  return Dis[T]!=inf;
}
inline int end(int&flow,int sum=inf,int ret=0){
  for(int now=T,p;now^S;now=dis[p^1])p=pre[now],sum=min(sum,w[p]);
  for(int now=T,p;now^S;now=dis[p^1])p=pre[now],w[p]-=sum,w[p^1]+=sum,ret+=cost[p];
  flow+=sum;return ret*sum;
}
inline int maxflow(int ans=0,int flow=0){
  while(spfa())ans+=end(flow);
  return -ans;
}
int main(){
  scanf("%d%d",&m,&n);
  for(int i=0;i<n;i++)
    for(int j=1;j<=m+i;j++)
      scanf("%d",&num[i+1][j]),Index[i+1][j]=++INDEX,++INDEX;
  build(1,1),printf("%d
",maxflow());
  build(inf,1),printf("%d
",maxflow());
  build(inf,inf),printf("%d
",maxflow());
  return 0;
}

分配问题

我真的懒得写了。。。

最长k可重区间集

离散化,值域[1,p]
之后从i向i+1(0<i<p)连边(容量为k),S向0连边(容量为k),p向T连边(容量为k)

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
	rg int x=0,f=1;rg char ch=getchar();
	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
const int maxn=501,maxN=1100,S=0,T=maxN-1,maxm=((1001+501)<<1)+233;
int l[maxn],r[maxn],num[maxn<<1];
int fir[maxN],dis[maxm],nxt[maxm],w[maxm],cost[maxm],id=1;
il vd link(const int&x,const int&y,const int&_w,const int&_c){nxt[++id]=fir[x],fir[x]=id,dis[id]=y,w[id]=_w,cost[id]=_c;}
il vd Link(int x,int y,int _w,int _c){link(x,y,_w,_c),link(y,x,0,-_c);}
il bool SPFA(int&c){
	sta int que[maxN],hd,tl,dist[maxN],lst[maxN];
	sta bool inque[maxN]={0};
	memset(dist,63,sizeof dist);memset(lst,0,sizeof lst);
	hd=tl=0;que[tl++]=S;inque[S]=1;dist[S]=0;
	while(hd^tl){
		sta int x;x=que[hd];
		for(rg int i=fir[x];i;i=nxt[i])
			if(dist[x]+cost[i]<dist[dis[i]]&&w[i]){
				dist[dis[i]]=dist[x]+cost[i];lst[dis[i]]=i;
				if(!inque[dis[i]])inque[dis[i]]=1,que[tl++]=dis[i],tl%=maxN;
			}
		++hd;hd%=maxN;inque[x]=0;
	}
	if(lst[T]==0)return 0;
	int flow=233333333;
	for(rg int i=lst[T];i;i=lst[dis[i^1]])flow=std::min(flow,w[i]);
	for(rg int i=lst[T];i;i=lst[dis[i^1]])c+=cost[i]*flow,w[i]-=flow,w[i^1]+=flow;
	return 1;
}
int main(){
	int n=gi(),k=gi(),p;
	for(rg int i=1;i<=n;++i){
		l[i]=gi(),r[i]=gi();
		num[++num[0]]=l[i],num[++num[0]]=r[i];
	}
	std::sort(num+1,num+2*n+1);
	p=std::unique(num+1,num+2*n+1)-num-1;
	for(rg int i=1;i<=n;++i)l[i]=std::lower_bound(num+1,num+p+1,l[i])-num,r[i]=std::lower_bound(num+1,num+p+1,r[i])-num;
	for(rg int i=0;i<p;++i)Link(i,i+1,k,0);
	for(rg int i=1;i<=n;++i)Link(l[i],r[i],1,-(num[r[i]]-num[l[i]]));
	Link(p,T,k,0);
	int c=0;while(SPFA(c));
	printf("%d
",-c);
	return 0;
}

餐巾计划

费用流裸题(要烂尾了)

#include<cstdio>
#include<algorithm>
#define X(o) ((o)<<1)
#define Y(o) ((o)<<1|1)
#define t (dis[i])
#define rg register
using namespace std;
int n,r[222],P,fast,slow,fastc,slowc;
const int maxd=420,maxm=23333,S=410,T=411,inf=233333333;
inline int gi() {
	rg int x=0;
	rg char ch=getchar();
	while(ch>'9'||ch<'0')ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x;
}
int fir[maxd],nxt[maxm],dis[maxm],w[maxm],cost[maxm],id=1;
inline void add(int a,int b,int c,int d){
	nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c,cost[id]=d;
	if(c)add(b,a,0,-d);
}
inline void build(){
	for(rg int i=1;i<=n;i++){
		add(S,X(i),r[i],0),add(S,Y(i),inf,P);
		add(Y(i),T,r[i],0);
		add(X(i),X(i+1),inf,0);
		if(i+fast<=n)add(X(i),Y(i+fast),inf,fastc);
		if(i+slow<=n)add(X(i),Y(i+slow),inf,slowc);
	}
}
inline bool spfa(int&F,int&C){
	int que[maxd],pre[maxd],Dis[maxd];bool inque[maxd]={0};
	rg int hd=1,tl=1;
	que[tl++]=S,inque[S]=1;
	for(rg int i=1;i<=Y(n);i++)Dis[i]=inf;Dis[T]=inf,Dis[S]=0;
	while(hd^tl){
		rg int now=que[hd];
		for(rg int i=fir[now];i;i=nxt[i])
			if(w[i]>0&&Dis[t]>Dis[now]+cost[i]){
				Dis[t]=Dis[now]+cost[i],pre[t]=i;
				if(!inque[t])que[tl++]=t,tl%=maxd,inque[t]=1;
			}
		hd=(hd+1)%maxd,inque[now]=0;
	}
	if(Dis[T]==inf)return 0;
	rg int sum=inf;
	for(int now=T,p;now^S;now=dis[p^1])p=pre[now],sum=min(sum,w[p]);
	for(int now=T,p;now^S;now=dis[p^1])p=pre[now],w[p]-=sum,w[p^1]+=sum,C+=cost[p]*sum;
	F+=sum;
	return 1;
}
inline int mincost(int Flow=0,int Cost=0){
	while(spfa(Flow,Cost));return Cost;
}
int main(){
	n=gi();
	for(rg int i=1;i<=n;i++)r[i]=gi();
	P=gi(),fast=gi(),fastc=gi(),slow=gi(),slowc=gi();
	build();
	printf("%d
",mincost());
	return 0;
}

最长k可重区间集

直接看我link部分吧。。

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
	rg int x=0,f=1;rg char ch=getchar();
	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
const int maxn=501,maxN=1100,S=0,T=maxN-1,maxm=((1001+501)<<1)+233;
int l[maxn],r[maxn],num[maxn<<1];
int fir[maxN],dis[maxm],nxt[maxm],w[maxm],cost[maxm],id=1;
il vd link(const int&x,const int&y,const int&_w,const int&_c){nxt[++id]=fir[x],fir[x]=id,dis[id]=y,w[id]=_w,cost[id]=_c;}
il vd Link(int x,int y,int _w,int _c){link(x,y,_w,_c),link(y,x,0,-_c);}
il bool SPFA(int&c){
	sta int que[maxN],hd,tl,dist[maxN],lst[maxN];
	sta bool inque[maxN]={0};
	memset(dist,63,sizeof dist);memset(lst,0,sizeof lst);
	hd=tl=0;que[tl++]=S;inque[S]=1;dist[S]=0;
	while(hd^tl){
		sta int x;x=que[hd];
		for(rg int i=fir[x];i;i=nxt[i])
			if(dist[x]+cost[i]<dist[dis[i]]&&w[i]){
				dist[dis[i]]=dist[x]+cost[i];lst[dis[i]]=i;
				if(!inque[dis[i]])inque[dis[i]]=1,que[tl++]=dis[i],tl%=maxN;
			}
		++hd;hd%=maxN;inque[x]=0;
	}
	if(lst[T]==0)return 0;
	int flow=233333333;
	for(rg int i=lst[T];i;i=lst[dis[i^1]])flow=std::min(flow,w[i]);
	for(rg int i=lst[T];i;i=lst[dis[i^1]])c+=cost[i]*flow,w[i]-=flow,w[i^1]+=flow;
	return 1;
}
int main(){
	int n=gi(),k=gi(),p;
	for(rg int i=1;i<=n;++i){
		l[i]=gi(),r[i]=gi();
		num[++num[0]]=l[i],num[++num[0]]=r[i];
	}
	std::sort(num+1,num+2*n+1);
	p=std::unique(num+1,num+2*n+1)-num-1;
	for(rg int i=1;i<=n;++i)l[i]=std::lower_bound(num+1,num+p+1,l[i])-num,r[i]=std::lower_bound(num+1,num+p+1,r[i])-num;
	for(rg int i=0;i<p;++i)Link(i,i+1,k,0);
	for(rg int i=1;i<=n;++i)Link(l[i],r[i],1,-(num[r[i]]-num[l[i]]));
	Link(p,T,k,0);
	int c=0;while(SPFA(c));
	printf("%d
",-c);
	return 0;
}

最长k可重线段集

与上道题一毛一样,特判与y轴平行的线段。

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define il inline
#define rg register
#define vd void
#define sta static
#define int long long
il int gi(){
	rg int x=0,f=1;rg char ch=getchar();
	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
const int maxn=501,maxN=1100,S=0,T=maxN-1,maxm=((1001+501)<<1)+233;
int l[maxn],r[maxn],len[maxn],num[maxn<<1];
int fir[maxN],dis[maxm],nxt[maxm],w[maxm],cost[maxm],id=1;
il vd link(const int&x,const int&y,const int&_w,const int&_c){nxt[++id]=fir[x],fir[x]=id,dis[id]=y,w[id]=_w,cost[id]=_c;}
il vd Link(int x,int y,int _w,int _c){link(x,y,_w,_c),link(y,x,0,-_c);}
il bool SPFA(int&c){
	sta int que[maxN],hd,tl,dist[maxN],lst[maxN];
	sta bool inque[maxN]={0};
	memset(dist,63,sizeof dist);memset(lst,0,sizeof lst);
	hd=tl=0;que[tl++]=S;inque[S]=1;dist[S]=0;
	while(hd^tl){
		sta int x;x=que[hd];
		for(rg int i=fir[x];i;i=nxt[i])
			if(dist[x]+cost[i]<dist[dis[i]]&&w[i]){
				dist[dis[i]]=dist[x]+cost[i];lst[dis[i]]=i;
				if(!inque[dis[i]])inque[dis[i]]=1,que[tl++]=dis[i],tl%=maxN;
			}
		++hd;hd%=maxN;inque[x]=0;
	}
	if(lst[T]==0)return 0;
	int flow=233333333;
	for(rg int i=lst[T];i;i=lst[dis[i^1]])
		flow=std::min(flow,w[i]);
	for(rg int i=lst[T];i;i=lst[dis[i^1]])c+=cost[i]*flow,w[i]-=flow,w[i^1]+=flow;
	return 1;
}
main(){
	int n=gi(),k=gi(),p;
	for(rg int i=1;i<=n;++i){
		sta int x1,x2,y1,y2;
		x1=gi(),y1=gi(),x2=gi(),y2=gi();len[i]=(int)(sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)));
		if(x1>x2)std::swap(x1,x2),std::swap(y1,y2);
		x1<<=1,x2<<=1;x1==x2?++x2:++x1;
		l[i]=x1,r[i]=x2;
		num[++num[0]]=l[i],num[++num[0]]=r[i];
	}
	std::sort(num+1,num+2*n+1);
	p=std::unique(num+1,num+2*n+1)-num-1;
	for(rg int i=1;i<=n;++i)l[i]=std::lower_bound(num+1,num+p+1,l[i])-num,r[i]=std::lower_bound(num+1,num+p+1,r[i])-num;
	for(rg int i=0;i<p;++i)Link(i,i+1,k,0);
	for(rg int i=1;i<=n;++i)Link(l[i],r[i],1,-len[i]);
	Link(p,T,k,0);
	int c=0;while(SPFA(c));
	printf("%lld
",-c);
	return 0;
}
原文地址:https://www.cnblogs.com/xzz_233/p/8195110.html