方格取数 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放人数字0。如下图所示(见样例 ,黄色和蓝色分别为两次走的路线,其中绿色的格子为黄色和蓝色共同走过的):
某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角的B 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。此人从A点到B点共走两次,试找出2条这样的路径,使得取得的数之和为最大 。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
有多组测试数据,每组格式如下: 第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Output | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
与输入对应,有多组输出,每组只需输出一个整数,表示2条路径上取得的最大的和。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Sample Input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8 2 3 13 2 6 6 3 5 7 4 4 14 5 2 21 5 6 4 6 3 15 7 2 14 0 0 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Sample Output | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
67 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Source | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
NOIp2000提高组 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Recommend | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
黄李龙 |
很难贪心到点的一个题。最开始是这样想的:BFS找出第一条路,然后DP找出第二条路,为什么不两次dp呢?bfs记录路径是很方便的。每一条路最贪心去做。样例过了,但是WA了、
原因是这样的:
我输入了一组这样的数据:
5
1 1 1 1 1
1 1 1 1 2
1 2 1 1 1
1 1 1 1 1
1 2 1 1 1
第一遍走的路径是:(1,1)(1,2)(2,2)(3,2)(4,2)(5,2)(5,3)(5,4)(5,5)。第一次搜之后确实是保证了第一次的局部最优,第二次DP也保证了第二次的局部最优,但是整体最优并没有保证,所以这个思路是不够贪心的。
所以正确的思路应该是这样的:BFS漫无目地的去搜,对于任何一条路径,搜到了终点的时候,就dp一次,这样就保证了整体最优。
思路:BFS搜到终点,记录路径,然后路径上所有点变成0,然后DP一下,然后再把路径上原来的值赋回去、最终总能有最优解产生。
我们分步来详解:
首先是变量:
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
struct zuobiao
{
int cont;
int jilu[30][2];//记录BFS路径
int x,y,output;
}now,nex;
int a[15][15];//图
int fx[2]={0,1};//两种走法
int fy[2]={1,0};
int dp[15][15];//dp用
int jilu3[30];//记录变成0的点的值,恢复用
int n;
int maxn;//最终解
广搜+dp的核心部分代码:
void bfs(int x,int y)//起点未处理.
{
now.x=x;
now.y=y;
now.output=0;
for(int i=0;i<30;i++)
{
now.jilu[i][0]=-1;
now.jilu[i][1]=-1;
}
now.cont=0;
queue<zuobiao >s;
s.push(now);//初始化
while(!s.empty())
{
now=s.front();
nex=now;
if(now.x==n&&now.y==n)//如果搜到了终点、
{
for(int i=0;i<now.cont;i++)//把这条路径上的点变成0
{
int x=now.jilu[i][0];
int y=now.jilu[i][1];
jilu3[i]=a[x][y];//同时用这个数组记录这么些个值。
a[x][y]=0;
}
memset(dp,0,sizeof(dp));//初始化dp数组
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=max(dp[i-1][j]+a[i][j],dp[i][j-1]+a[i][j]);//dp的状态转移方程。
}
}
for(int i=0;i>now.cont;i++)//再赋值回去
{
int x=now.jilu[i][0];
int y=now.jilu[i][1];
a[x][y]=jilu3[i];
}
if(now.output+dp[n][n]>maxn)//更新最优解
{
maxn=now.output+dp[n][n];
}
}
s.pop();
for(int i=0;i<2;i++)//两种走法
{
nex.x=now.x+fx[i];
nex.y=now.y+fy[i];
if(nex.x>=1&&nex.x<=n&&nex.y>=1&&nex.y<=n)//如果当前走到的位子符合条件
{
nex.output=now.output+a[nex.x][nex.y];
if(a[nex.x][nex.y]!=0)//如果这个点的值不为0
{
nex.jilu[now.cont][0]=nex.x;
nex.jilu[now.cont][1]=nex.y;//记录路径
nex.cont=now.cont+1;
}
s.push(nex);
}
}
}
}
完整的AC代码:
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
struct zuobiao
{
int cont;
int jilu[30][2];
int x,y,output;
}now,nex;
int a[15][15];
int fx[2]={0,1};
int fy[2]={1,0};
int dp[15][15];
int jilu3[30];
int n;
int maxn;
void bfs(int x,int y)//起点未处理.
{
now.x=x;
now.y=y;
now.output=0;
for(int i=0;i<30;i++)
{
now.jilu[i][0]=-1;
now.jilu[i][1]=-1;
}
now.cont=0;
queue<zuobiao >s;
s.push(now);
while(!s.empty())
{
now=s.front();
nex=now;
//printf("%d %d %d\n",now.x,now.y,now.output);
if(now.x==n&&now.y==n)
{
for(int i=0;i<now.cont;i++)
{
int x=now.jilu[i][0];
int y=now.jilu[i][1];
jilu3[i]=a[x][y];
a[x][y]=0;
}
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j]=max(dp[i-1][j]+a[i][j],dp[i][j-1]+a[i][j]);
}
}
for(int i=0;i>now.cont;i++)
{
int x=now.jilu[i][0];
int y=now.jilu[i][1];
a[x][y]=jilu3[i];
}
if(now.output+dp[n][n]>maxn)
{
maxn=now.output+dp[n][n];
}
}
s.pop();
for(int i=0;i<2;i++)
{
nex.x=now.x+fx[i];
nex.y=now.y+fy[i];
if(nex.x>=1&&nex.x<=n&&nex.y>=1&&nex.y<=n)
{
nex.output=now.output+a[nex.x][nex.y];
if(a[nex.x][nex.y]!=0)
{
nex.jilu[now.cont][0]=nex.x;
nex.jilu[now.cont][1]=nex.y;
nex.cont=now.cont+1;
}
s.push(nex);
// printf("%d\n",nex.output);
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j]=0;
}
}
while(1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==0&&y==0&&z==0)break;
else a[x][y]=z;
}
maxn=0;
bfs(1,1);
printf("%d\n",maxn);
}
}