• 网络流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;
    }
    
  • 相关阅读:
    C#--带参SQL语句数通用数据访问类
    VS 2017产品密匙
    关于编码中的字符和字节问题
    关于C++中的cin用法
    C++基础(一、基本语法,Hello World)
    Oracle查看用户所在的表空间
    静态变量、枚举、以及静态代码块的使用场景
    Java 枚举(enum) 详解7种常见的用法
    第一章 对象和封装
    摘抄Java反射
  • 原文地址:https://www.cnblogs.com/xzz_233/p/8195110.html
Copyright © 2020-2023  润新知