【算法】P1004 方格取数
题目大意:
设有N×N的方格图(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):
A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 0 0 0 0 0 7 0 0 0 0 0 0 14 0 0 0 0 0 21 0 0 0 4 0 0 0 0 15 0 0 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 B
某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。 此人从A点到B点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入:
输入的第一行为一个整数N(表示N×N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
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
输出:
只需输出一个整数,表示2条路径上取得的最大的和。
67
思路:
看到这道题,我第一个想法便是通过dp数组,直接将不在同一条路的值选择两个最大的值进行相加。但是最后只得到了10分,然后我发现这道题是存在陷阱的,因为两次走的路线是可以交叉的,而现在这段时间我仍旧在思考如何通过dp数组完成这个操作,暂时还没好的解决方法,等我想到了并尝试了之后,会跟网上大神的思路进行对比,到时候应该能给我更多的启发。
言归正传,我现在ac的算法是通过图遍历解决的,在此算法中,定义两点是互相连接的当且仅当两个点之间不存在其他的可插入节点,即a(x1, y1), b(x2, y2)互相连接,则不存在点满足(x1<=x<=x2 && y1<=y<=y2))。之后就是直接深搜最大值。直接上代码说:
1 #include <iostream> 2 #include <cstdio> 3 #include <list> 4 #include <algorithm> 5 6 using namespace std; 7 8 #define MAXN 100 9 struct Point{ 10 int x; 11 int y; 12 int val; 13 }; 14 15 bool cmp(Point p1, Point p2){ 16 return p1.x<=p2.x && p1.y<=p2.y; 17 } 18 19 bool gra[MAXN][MAXN]; 20 bool vis[MAXN]; 21 Point pos[MAXN]; 22 int maxValue = 0; 23 int curValue = 0; 24 25 // 计算路径中所有的拥有一个回路的花费 26 void dfs(int curP, int type, bool ctn, int totalNum){ // type: 0 去, 1 回 从0开始 ctn: 是否可以继续走被vis过的点 27 if(type == 0){ // 往前走 28 if(curP == totalNum) 29 dfs(curP, 1, true, totalNum); 30 else 31 for(int i=curP+1; i<=totalNum; i++){ 32 if(gra[curP][i]){ // 可以往下继续 33 vis[i] = 1; 34 curValue += pos[i].val; 35 dfs(i, 0, ctn, totalNum); 36 curValue -= pos[i].val; 37 vis[i] = 0; 38 } 39 } 40 } 41 else{ // 往回走,可以走到vis过的点,但出现未vis过的点时不能再走vis过的 42 if(gra[curP][0]==1) 43 maxValue = max(maxValue, curValue); 44 45 else{ 46 int i; 47 48 for(i=curP-1; i>=1; i--){ 49 if(gra[curP][i] && (!vis[i] || (ctn && vis[i]))){ 50 bool temp = ctn; 51 if(!vis[i]){ 52 ctn = false; 53 curValue += pos[i].val; 54 } 55 dfs(i, 1, ctn, totalNum); 56 if(!vis[i]) curValue -= pos[i].val; 57 ctn = temp; 58 } 59 } 60 if(i==0) 61 maxValue = max(maxValue, curValue); 62 } 63 } 64 } 65 66 67 int main(){ 68 int N; 69 scanf("%d", &N); 70 int px, py, val; 71 int count = 0; 72 pos[count++] = {0, 0, 0}; 73 while(scanf("%d %d %d", &px, &py, &val)==3 && (px!=0 || py!=0 || val!=0)){ 74 // 直接使用vector?抑或数组 75 pos[count++] = {px, py, val}; 76 } 77 pos[count] = {N+1, N+1, 0}; 78 sort(pos, pos+count, cmp); 79 80 // 初始化,矩阵边缘为1 81 for(int i=0; i<=count; i++){ 82 vis[i] = 0; 83 for(int j=0; j<=count; j++) 84 gra[i][j] = (i==0 || i==count || j==0 || j==count) ? 1 : 0; 85 } 86 gra[0][0] = 0, gra[0][count] = 0; 87 gra[count][0] = 0, gra[count][count] = 0; 88 89 // 若两点可连通则为1,矩阵是对称的 90 for(int i=1; i<count; i++) 91 for(int j=i+1; j<count; j++) 92 if(pos[j].x>=pos[i].x && pos[j].y>=pos[i].y){ 93 gra[i][j] = 1; 94 gra[i][count] = 0; 95 gra[j][i] = 1; 96 gra[j][0] = 0; 97 gra[0][j] = 0; 98 gra[count][i] = 0; 99 } 100 101 // 删除能够通过其他节点连通的线 102 for(int i=1; i<count; i++) 103 for(int j=i+1; j<count; j++) 104 if(gra[i][j] == 1){ 105 for(int k=j+1; k<count; k++) 106 if(gra[j][k] == 1){ 107 gra[i][k] = 0; 108 gra[k][i] = 0; 109 } 110 } 111 112 dfs(0, 0, true, count); 113 printf("%d", maxValue); 114 return 0; 115 }