noip 2000 Day2 T6 方格取数

41 篇文章 0 订阅
20 篇文章 0 订阅

题面

在这里插入图片描述

分析

学过网络流的同志都不难看出,本题可以用网络流,将有数的方格看作点,根据位置关系(只能往右下走)来建图,然后跑两遍最大流,每跑一次就更新权值即可

代码?太懒难得写

当然本题还可以用搜索,从起点开始dfs,遇到点就更新权值且累加ans,回溯时就把权值放回去就好,每次到终点时维护一下maxx和maxxx(第一大和第二大)

还没写过这种,只是有个思路

我其实做这道题是想练一下动归(蒟蒻动归太弱啦),一开始想的是令f[i][j]指走到(i,j)的最大值,易得 f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i ] [ j − 1 ] ) f[i][j]=max(f[i-1][j],f[i][j-1]) f[i][j]=max(f[i1][j],f[i][j1]),然后更新权值走两遍动归

结果突然发现好像无法更新权值,只好放弃

后面题解里给出比较好的解题思路:
令f[i][j][k][l]指第1个人走到(i,j),第二个人走到(k,l)时的最大权值,则有
f [ i ] [ j ] [ k ] [ l ] = m a x ( s i t i u a t i o n 1 , s i t i u a t i o n 2 ) + w f[i][j][k][l]=max(sitiuation1,sitiuation2)+w f[i][j][k][l]=max(sitiuation1,sitiuation2)+w
w = ( 第 一 个 人 和 第 二 个 人 在 同 一 位 置 ) ? G [ i ] [ j ] : G [ i ] [ j ] + G [ k ] [ l ] w=(第一个人和第二个人在同一位置)?G[i][j]:G[i][j]+G[k][l] w=()G[i][j]:G[i][j]+G[k][l]
s i t i u a t i o n 1 = m a x ( f [ i ] [ j − 1 ] [ k ] [ l − 1 ] , f [ i ] [ j − 1 ] [ k − 1 ] [ l ] ) sitiuation1=max(f[i][j-1][k][l-1],f[i][j-1][k-1][l]) sitiuation1=max(f[i][j1][k][l1],f[i][j1][k1][l])
s i t i u a t i o n 2 = m a x ( f [ i − 1 ] [ j ] [ k ] [ l − 1 ] , f [ i − 1 ] [ j ] [ k − 1 ] [ l ] ) sitiuation2=max(f[i-1][j][k][l-1],f[i-1][j][k-1][l]) sitiuation2=max(f[i1][j][k][l1],f[i1][j][k1][l])

这样写可能阅读体验要好些
一个四重循环了事(其实还可以优化的,正在调试中(update 2019.11.17:真有意思,调到退役了都没调出来))

code

四重循环
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(int i=start;i<=end;i++)
#define clean(arry,num); memset(arry,num,sizeof(arry));
#define max(a,b) ((a>b)?a:b)//
#define min(a,b) (a<b)?a:b
int n;
const int maxn=12;
int g[maxn][maxn];
int dp[maxn][maxn][maxn][maxn];
inline int read()
{
	int ans=0;char r=getchar();
	while(r>'9'||r<'0')r=getchar();
	while(r>='0'&&r<='9')
	{
		ans=ans*10+r-'0';
		r=getchar();
	}
	return ans;
}
int main()
{
	freopen("datain.txt","r",stdin);
	clean(g,0);clean(dp,0);
	n=read();
	while(true)
	{
		int x,y,p;
		x=read();y=read();p=read();
		if(x==0&&y==0&&p==0)break;//
		g[x][y]=p;
	}
	loop(i,1,n)
	    loop(j,1,n)
		    loop(k,1,n)
			    loop(m,1,n)
				    dp[i][j][k][m]=max(max(dp[i-1][j][k-1][m],dp[i-1][j][k][m-1]),max(dp[i][j-1][k-1][m],dp[i][j-1][k][m-1]))+((i==k&&j==m)?g[i][j]:g[i][j]+g[k][m]);
	printf("%d",dp[n][n][n][n]);
	return 0;
}

学到的东西

1.关于宏
宏的本质就是替换,它只做替换,不做其他的事
上面程序中的min宏就是一个很好的例子
比如我这样写宏

#define min(a,b) (a<b)?a:b

然后这样用宏

int minn=min(min(a,b),min(a-1,b-1));

然后替换出来就是这样子的

int minn=((a<b)?a:b<(a-1<b-1)?a-1:b-1)?(a<b)?a:b:(a-1<b-1)?a-1:b-1

仔细分析就会发现有问题,这会导致我们不想要的结果
但如果我们给min加个括号,同样用宏

#define min(a,b) (a<b)?a:b

就有

int minn=((((a<b)?a:b)<(a-1<b-1)?a-1:b-1))?((a<b)?a:b):(a-1<b-1)?a-1:b-1))

很明显没有问题了
这就是括号的问题,加上括号可以让优先级明确,以避免很多玄学错误


update:2019/3/16
最好不要在宏里面带入函数,比如一个min宏中带一个递归函数,不然死的很惨的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值