5104 I-country 0x50「动态规划」例题
描述
在 N*M 的矩阵中,每个格子有一个权值,要求寻找一个包含 K 个格子的凸连通块(连通块中间没有空缺,并且轮廓是凸的,如书中图片所示),使这个连通块中的格子的权值和最大。求出这个最大的权值和,并给出连通块的具体方案。本题有SPJ,输出任意一种方案即可。N,M≤15,K≤225。
According to top-secret A-country plans, I-country is divided into N*M equal squares, each square contains some oil resources. They want to occupy all the territory of I-country, but the UN (United Nations) will allow them to occupy only K squares. Of course, A-country want to get control over as many oil as possible, but, they will have to guard all their territory. So, they need their territory to be easy-controlled, i.e. from any square to any it must be possible to get moving only along two directions (selected from the next list: left, right, up, down; for different squares pairs of directions may differ).
You are to write a program, which determinies, what squares will be occupyed by A-country. If there are several solutions, you may output any.
输入格式
On the first line of input there are 3 integer numbers N,M,K (1<=N,M<=15, 0<=K<=N*M). Next N lines contains M integers each, which are the number of oil resource on that square. Each of this numbers lies in range of 0 to 1000.
输出格式
On the first line of output, write string "Oil : X", where integer number X --- the maximal number of oil which can be controlled by A-country. Next you should output K pairs of numbers --- coordinates of the squares which will be occupied by A-country. The first coordinate is number of row (top to bottom, starting from 1), second is number of column (left to right, starting from 1).
样例输入
2 3 4 10 20 30 40 2 3
样例输出
Oil : 100 1 1 1 2 1 3 2 1
来源
SGU167
本题校验器(SPJ)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; //一些定义 const int ACCEPT = 0; const int WRONG_ANSWER = 1; //fstd 标准输出 fout 选手输出 fin 标准输入 FILE *fstd,*fout,*fin; int n, m, k, a[20][20], v[20][20], ans, val; //执行比较操作。 bool DoCompare(){ fscanf(fin, "%d%d%d", &n, &m, &k); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) fscanf(fin, "%d", &a[i][j]); fscanf(fstd, "%*s%*s%d", &ans); fscanf(fout, "%*s%*s%d", &val); // 答案不对 if (val != ans) return false; for (int i = 1; i <= k; i++) { int x, y; fscanf(fout, "%d%d", &x, &y); // 格子越界或者有重复 if (x < 1 || y < 1 || x > n || y > m || v[x][y]) return false; v[x][y] = 1; val -= a[x][y]; } // 输出的格子加起来不等于答案 if (val) return false; // 检查凸性 for (int i = 1; i <= n; i++) { int cnt = 0, l = m, r = 1; for (int j = 1; j <= m; j++) if (v[i][j]) cnt++, l = min(l, j), r = max(r, j); if (cnt == 0) continue; // 输出的格子在一行里不连续 if (r - l + 1 != cnt) return false; } for (int j = 1; j <= m; j++) { int cnt = 0, l = n, r = 1; for (int i = 1; i <= n; i++) if (v[i][j]) cnt++, l = min(l, i), r = max(r, i); if (cnt == 0) continue; // 输出的格子在一列里不连续 if (r - l + 1 != cnt) return false; } return true; } int main(int argc, char* argv[]) { if(argc!=4){ printf("参数不足 %d",argc); return -1; } //打开文件 if(NULL==(fstd=fopen(argv[1],"r"))){ return -1; } if(NULL==(fout=fopen(argv[2],"r"))){ return -1; } if(NULL==(fin=fopen(argv[3],"r"))){ return -1; } if(DoCompare()){ return ACCEPT; }else{ return WRONG_ANSWER; } }