K取方格数

给定矩阵 从1,1到n~m设计k条线路 取走格子中的数(重复经过只取一次)k条线路和的最大值是多少

技巧:

  1. 每个点拆成入点和出点 实现点边的转化
  2. 通过限制费用大小和流量大小 来实现被取走的次数和贡献
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;

const int N=55;
const double eps=1e-9;
const int INF=0x3f3f3f3f;
int read()
{
	int x=0,f=0,c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return f?-x:x;
}

struct Edge
{
	int to,next,w,c;
}e[N*N*8];
int head[N*N*2],cnt=1;
void _add(int a,int b,int c,int d){e[++cnt]=(Edge){b,head[a],c,d};head[a]=cnt;}
void add(int a,int b,int c,int d){ 
//printf("%d %d %d %d\n",a,b,c,d);
_add(a,b,c,d); _add(b,a,0,-d);}
int maxflow,ans,n,s,t,k;
int F(int x,int y,int z){ return (x-1)*n+y+z*n*n; }

queue<int> q;
bool inq[N*N*2]; 
int d[N*N*2],incf[N*N*2],pre[N*N*2];
//spfa 多次拓展 但是进入队列只有一次 
bool spfa()
{
	while(q.size()) q.pop();
	memset(inq,0,sizeof inq); memset(d,0xcf,sizeof d);
	q.push(1); inq[1]=1; incf[1]=INF; d[1]=0;
	while(q.size())
	{
		int x=q.front(); q.pop(); inq[x]=0;//注意出队标记 
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;
			if(!e[i].w) continue;
			if(d[y]<d[x]+e[i].c)
			{
				d[y]=d[x]+e[i].c;
				incf[y]=min(incf[x],e[i].w); pre[y]=i;
				if(!inq[y]) inq[y]=1,q.push(y);//注意入队标记 
			}
		}
	}
	return d[t]!=0xcfcfcfcf;
}

void update()
{
	 int x=t;
	 while(x!=s)
	 {
	 	int i=pre[x];
	 	e[i].w-=incf[t]; e[i^1].w+=incf[t];
	 	x=e[i^1].to;
	 }
	 maxflow+=incf[t];
	 ans+=d[t]*incf[t];
}

int main()
{	
	n=read(); k=read();
	s=1; t=n*n*2;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) 
		{
			int x=read();
			add(F(i,j,0),F(i,j,1),1,x); add(F(i,j,0),F(i,j,1),k-1,0);
			if(j<n) add(F(i,j,1),F(i,j+1,0),k,0);
			if(i<n) add(F(i,j,1),F(i+1,j,0),k,0);
		}
	while(spfa()) update();
	
	printf("%d",ans);
	return 0;
}
posted @   __iostream  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示