UVA - 10558 A Brief Gerrymander

来源:互联网 发布:ai mac版 编辑:程序博客网 时间:2024/05/01 00:47

题意:一个棋盘,横竖线都是从1到100标号(竖线从左到右标,横线从下到上标),输入n表示有n个被标记的格子,是给出这个格子的左下角坐标,然后输入m,在输入m个数,表示在这些竖线的地方切开棋盘(其实只切了m-2刀,因为2刀必须是1和100,相当于没有),然后输入A,表示你要在横上上切A刀(其实也只是A-2刀,因为2刀必须在横线的1和100)。那么就可以把棋盘很多个大小不一的方块(矩形),只要这些方块中有被标记的小格子(1个或多个),那么这个方块就是一个选区,我们是要使到选区的个数最多

思路: 有想着肯定是要枚举(i,j)行之间的最大值的,但是还是写不出来,看了题解,使用预处理[i,j]间的个数,然后就可以枚举啦 ,f[i][j]表示在前j行切i刀的最大值,并记录切的行数,因为第1,100 行是一定要切的,所以从第2刀开始枚举,j行从i+1开始就可以了,还有就是这道题具有最优子结构,就是第前j行切i刀的最大位置,一定是包含前p[i][j]行切i-1刀的结果,所以我们就得到打印结果的方式了

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 110;int N,S,A,g[MAXN][MAXN],f[MAXN][MAXN],street[MAXN];int t[MAXN][MAXN],st[MAXN][MAXN][MAXN],s[MAXN][MAXN],p[MAXN][MAXN];int init(){    int i,j,k,flag,x,y;    scanf("%d",&N);    if (N == -1)        return 0;    memset(g,0,sizeof(g));    for (i = 0; i < N; i++){        scanf("%d%d",&y,&x);        g[x][y] = 1;    }    scanf("%d",&S);    for (i = 0; i < S; i++)        scanf("%d",&street[i]);    scanf("%d",&A);    memset(t,0,sizeof(t));    for (i = 2; i <= 100; i++)        for (j = 1; j < S; j++){            flag = 0;            for (k = street[j-1]; k < street[j]; k++)                if (g[i-1][k])   //是左下角标记                    flag = 1;            if (flag)                t[i][j] = 1;  //前i行前j刀是否有标记的        }    memset(s,0,sizeof(s));    memset(st,0,sizeof(st));    for (i = 1; i < 100; i ++)        for (j = i + 1; j <= 100; j++){            for (k = 1; k < S; k++)                st[i][j][k] |= st[i][j-1][k];   //确定在竖切的(i,j)区域的块数            for (k = 1; k < S; k++)    // 确定j行加进去后有没有                st[i][j][k] |= t[j][k];            for (k = 1; k < S; k++)   //确定有几个                if (st[i][j][k])                    s[i][j]++;        }    return 1;}void print(int i,int k){    if (k != 1)        print(i-1,p[i][k]);    printf(" %d",k);}void solve(){    int i,j,k,max;    memset(f,-1,sizeof(f));    for (i = 2; i <= 100; i++){        f[1][i] = s[1][i];        p[1][i] = 1;    }    for (i = 2; i < A; i++)        for (j = i + 1; j <= 100; j++){            for (k = i; k < j; k++)                if (f[i-1][k]+s[k][j] > f[i][j]){                    f[i][j] = f[i-1][k] + s[k][j];                    p[i][j] = k;                }        }    printf("%d",A);    print(A-1,100);    printf("\n");}int main(){    while (init())        solve();    return 0;}