noip2000提高组——方格取数【费用流 or dp】

本文探讨了如何将网络流算法与双向DP相结合,解决特定类型的问题。通过实例展示了解题过程,并对比了两种方法的适用场景。重点在于提供一种高效且灵活的解决方案策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题用的network flow。。
好高大上的网络流。

其实是可以写双向dp的   只是我没反应过来   当时就只写了网络流



网络流版

#include<cstring>
#include<cstdio>
#include<queue>
#define cle(a,b) memset(a,b,sizeof(a))
#define loop(i,j,k) for(int i=j;i<=k;i++)
#define MAXN (15)
using namespace std;
int n,ans;
int map[MAXN][MAXN];
struct edge{
	int u,v,w,ll,next;
}e[MAXN*MAXN*8];
int cnt=-1;
int head[MAXN*MAXN*2];
void adde(int u,int v,int w,int ll) {
	e[++cnt].v=v;
	e[cnt].u=u;
	e[cnt].w=w;
	e[cnt].ll=ll;
	e[cnt].next=head[u];
	head[u]=cnt;	
	e[++cnt].v=u;
	e[cnt].u=v;
	e[cnt].w=-w;
	e[cnt].ll=0;
	e[cnt].next=head[v];
	head[v]=cnt;
}
void readdata(){	
	scanf("%d",&n);	
	int u,v,w;
	while(1){
		scanf("%d",&u);
		if(!u)
		break;
		scanf("%d%d",&v,&w);
		map[u][v]=w;
	}
}
int change(int x,int y){
	return (x-1)*n+y;
}
void ready(){
	cle(head,-1);
	int now;
	loop(i,1,n){
		loop(j,1,n){		
			now=change(i,j);
			if(map[i][j])
			adde(now,now+n*n,map[i][j],1);
			adde(now,now+n*n,0,100);			
		}
	}	
	loop(i,1,n-1){
		loop(j,1,n-1){
			now=change(i,j);
			adde(now+n*n,now+n,0,100);
			adde(now+n*n,now+1,0,100);
		}
	}
	loop(j,1,n-1){
		now=change(n,j);
		adde(now+n*n,now+1,0,100);
		now=change(j,n);
		adde(now+n*n,now+n,0,100);
	}	
	adde(0,1,0,2);
	adde(n*n*2,n*n*2+1,0,2);
}
int dis[MAXN*MAXN*2];
int inq[MAXN*MAXN*2];
int fa[MAXN*MAXN*2];
queue<int>q;
bool re;
bool spfa(){
	cle(dis,-0x3f);
	cle(inq,0);
	cle(fa,-1);
	re=false;
	dis[0]=0;
	q.push(0);
	inq[0]=1;
	int cs;
	while(!q.empty()){
		cs=q.front();
		q.pop();
		inq[cs]=0;
		for(int i=head[cs];i!=-1;i=e[i].next){
			if(cs==7){
				int hehe=1;
			}
			if(e[i].ll==0)
			continue;
			int v=e[i].v;
			if(dis[v]<dis[cs]+e[i].w){
				dis[v]=dis[cs]+e[i].w;
				fa[v]=i;
				if(v==1+2*n*n)
					re=true;
				if(!inq[v]){
					inq[v]=1;
					q.push(v);
				}				
			}
		}
	}
	return re;
}
void solve(){
	int minll;
	int now;
	while(1){
		minll=0x3f3f3f3f;
		if(spfa()){
			now=2*n*n+1;
			while(now!=0){
				now=fa[now];
				minll=min(minll,e[now].ll);
				now=e[now].u;
			}
			now=2*n*n+1;
			while(now!=0){
				now=fa[now];
				e[now].ll-=minll;
				e[now^1].ll+=minll;
				now=e[now].u;
			}
			ans+=minll*dis[2*n*n+1];
		}
		else break;
	}
}
void print(){
	printf("%d\n",ans);
}
int main(){
	readdata();
	ready();
	solve();
	print();
}



dp版不想写了,,


### NOIP 2000 提高 方格问题分析 该问题属于经典的动态规划类题目,目标是在给定的一个二维矩阵中选若干个不相邻的字使得总和最大。此问题可以通过状态转移的方式解决。 #### 动态规划的核心思路 定义 `dp[i][j]` 表示到达第 `i` 行第 `j` 列时能够得的最大值之和[^1]。由于每次移动仅能向右或者向下,因此可以得出如下状态转移方程: 对于任意位置 `(i, j)` 的状态更新方式为: \[ dp[i][j] = \text{matrix}[i][j] + \max(dp[i-1][j], dp[i][j-1]) \] 其中需要注意边界条件处理以及初始值设定。当处于第一行或第一列时,路径的选择会受到限制[^2]。 #### 边界情况考虑 如果当前单元位于网格的第一行,则只能由左侧进入;同理,若当前位置处在首列,则唯一可能来自上方。这些特殊情况需单独初始化以确保计算准确性[^3]。 ```python def max_sum(matrix): m, n = len(matrix), len(matrix[0]) # 初始化 DP dp = [[0]*n for _ in range(m)] # 设置起点 dp[0][0] = matrix[0][0] # 填充第一行 for j in range(1, n): dp[0][j] = dp[0][j-1] + matrix[0][j] # 填充第一列 for i in range(1, m): dp[i][0] = dp[i-1][0] + matrix[i][0] # 完成剩余部分填充 for i in range(1,m): for j in range(1,n): dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + matrix[i][j] return dp[-1][-1] ``` 以上代码片段展示了如何通过构建辅助来记录每一步的最佳决策过程,并最终返回全局最优解。 #### 复杂度评估 时间复杂度主要决于遍历整个输入矩阵所需的操作次,即 O(M*N),这里 M 和 N 分别代表矩阵的高度与宽度。空间复杂度同样为 O(M*N),因为我们需要额外的空间存储中间结果以便后续访问[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值