CF#508 1038E Maximum Matching
题解:
感觉还是比较妙的,复杂度看上去很高(其实也很高),但是因为n只有100,所以还是可以过的。
考虑一个很暴力的状态f[i][j][x][y]表示考虑取区间i ~ j的方格,左右端点颜色分别是x, y.的最大值。
那么有如下转移
1,直接继承子区间的答案
f[i][j][x][y] = max(f[i][k][x][y], f[k + 1][j][x][y]);//因为子区间就这2种,毕竟子区间一定比当前区间小,因此不靠在端点上的区间一定已经被靠在端点上的区间给取过max了。
2,由2段子区间拼凑而来,相当于枚举中间断开的地方是选了那个块.//如果中间断开的地方的块没有被选,那么一定可以找到一个被选的块作为断点(如果找不到就说明这整个区间内只取了端点,再转移也没有什么意义。)
翻转操作是不需要考虑的,因为可以在初始化的地方就处理掉,因此只需要在转移的地方考虑一下乱序继承即可。
即正常的顺序是[i, l] + [l + 1, j] = [i, j];
乱序则可以支持[l + 1][j] + [i, l] = [i, j];
所以对于这2种情况都转移一下,转移的时候必须要求相接的地方颜色相同即可。
注意因为有子区间相加转移的地方,所以初始化为极小值的时候不要太小了,不然太小了直接一加就爆了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 110 5 #define ac 6 6 7 int n, ans; 8 int f[AC][AC][ac][ac]; 9 10 inline int read() 11 { 12 int x = 0;char c = getchar(); 13 while(c > '9' || c < '0') c = getchar(); 14 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 15 return x; 16 } 17 18 void pre() 19 { 20 n = read(); 21 memset(f, -63, sizeof(f)); 22 int a, b, c; 23 for(R i = 1; i <= n; i ++) 24 { 25 a = read(), b = read(), c = read(); 26 f[i][i][a][c] = f[i][i][c][a] = b; 27 } 28 } 29 30 inline void upmax(int &a, int b) 31 { 32 if(b > a) a = b; 33 } 34 35 void work() 36 { 37 for(R i = n; i; i --) 38 for(R j = i; j <= n; j ++) 39 for(R x = 1; x <= 4; x ++) 40 for(R y = 1; y <= 4; y ++) 41 { 42 for(R l = i; l < j; l ++) 43 { 44 upmax(f[i][j][x][y], max(f[i][l][x][y], f[l + 1][j][x][y])); 45 for(R k = 1; k <= 4; k ++) 46 { 47 upmax(f[i][j][x][y], f[i][l][x][k] + f[l + 1][j][k][y]); 48 upmax(f[i][j][x][y], f[i][l][k][y] + f[l + 1][j][x][k]); 49 } 50 } 51 upmax(ans, f[i][j][x][y]); 52 } 53 printf("%d\n", ans); 54 } 55 56 int main() 57 { 58 //freopen("in.in", "r", stdin); 59 pre(); 60 work(); 61 //fclose(stdin); 62 return 0; 63 }