uva10558
来源:互联网 发布:adsafe净网大师mac版 编辑:程序博客网 时间:2024/06/01 09:00
转载自别人的题解
题意:一个棋盘,横竖线都是从1到100标号(竖线从左到右标,横线从下到上标),输入n表示有n个被标记的格子,是给出这个格子的左下角坐标,然后输入m,在输入m个数,表示在这些竖线的地方切开棋盘(其实只切了m-2刀,因为2刀必须是1和100,相当于没有),然后输入A,表示你要在横上上切A刀(其实也只是A-2刀,因为2刀必须在横线的1和100)。那么就可以把棋盘很多个大小不一的方块(矩形),只要这些方块中有被标记的小格子(1个或多个),那么这个方块就是一个选区,我们是要使到选区的个数最多
要先预处理,我们先来说明几个数组做意义。首先题目已经切好了竖线,一共m条,那么整个正方形的棋盘就被分成了m-1个长条状的矩形。
数组only[i][j]的意思是在第j部分(原棋盘已经被分为了m-1个部分)第i条横线上的方块有没有被标记的方块,有为1,无为0,所以only数组可以设为bool型
数组f[i][j]的意思是在第j部分(原棋盘已经被分为了m-1个部分),从最底下的横线开始在第i条横线上的方块一共有多少行是有标记的方块的,是一个累加数组
也就是程序里面这个语句
only[i][k]=f[i][k]=0;
for(j=a[k]; j
#include <iostream>using namespace std;#include <cstring>#include <stdio.h>const int MAX = 110;bool g[MAX][MAX];//i,j坐标下有被标记bool only[MAX][MAX];//第j部分的第i条横线有标记bool vis[MAX][MAX]; int f[MAX][MAX];//j部分从最底下的横线开始在第i条横线上的方块总数int a[MAX];//标记竖线切割的地方int dp[MAX][MAX]; //表示在横线区间(i,100)选k条横线进行切割的最优解int s[MAX][MAX];//表示第i条横线到第j条横线之间有多少选区int path[MAX][MAX];int m,A;//竖,横要切几刀void init(){ int i,j,k; for(k=1; k<m; k++) for(i=1; i<100; i++) { only[i][k]=f[i][k]=0; for(j=a[k]; j<a[k+1]; j++) if(g[i][j]==1) { only[i][k]=1; break; } f[i][k]=only[i][k]; f[i][k]+=f[i-1][k]; } for(i=1; i<100; i++) for(j=i+1; j<=100; j++) { s[i][j]=0; for(k=1; k<m; k++) if(f[j-1][k]-f[i][k]+only[i][k]) s[i][j]++; } return ;}int DP(int p,int q) { int k,ans; if(vis[p][q]) return dp[p][q]; vis[p][q] = 1; if(q == 0) return dp[p][q] = s[p][100]; dp[p][q] = 0; for(int i = p + 1; i < 100; i++) { if(100 - i - 1 < q - 1) // 剩余的横线数要大于等于可以切的刀数量 break; ans = DP(i, q - 1);//在i的部分切了一刀 if(ans + s[p][i] > dp[p][q]) {//如果切完的选区数大于原来的就更新 dp[p][q] = ans + s[p][i]; path[p][q] = i; } } return dp[p][q];}void print_path(int i,int j) { int k; if(j <= 0) return; k = path[i][j]; printf(" %d",k); print_path(k, j - 1); return ;}/*int main() { int n; int p,q; while(1) { scanf("%d",&n); if(n == -1) break; memset(g,0,sizeof(g)); memset(a,0,sizeof(a)); for(int i = 1; i <= n; i++) { scanf("%d %d",&p,&q); g[p][q] = 1; } scanf("%d",&m); for(int i = 1; i <= m; i++) scanf("%d",&a[i]); scanf("%d",&A); memset(f,0,sizeof(f)); memset(only,0,sizeof(only)); for(int k = 1; k < m; k++)//竖线划分的第k部分 for(int i = 1; i < 100; i++) {//第i条横线 only[i][k] = f[i][k] = 0; for(int j = a[k]; j < a[k + 1]; j++) //第k部分的大小 if(g[i][j] == 1) { only[i][k] = 1; break; } f[i][k] = only[i][k]; f[i][k] += f[i - 1][k];//累加起来就是k部分最底下横线到i的所有标记数 } for(int i = 1; i < 100; i++) for(int j = i + 1; j <= 100; j++) { s[i][j] = 0; for(int k = 1;k < m; k++) if(f[j - 1][k] - f[i][k] + only[i][k])//j - 1到i之间是否有标记 s[i][j]++; } //init(); memset(vis,0,sizeof(vis)); DP(1,A - 2); printf("%d",A); printf(" 1"); print_path(1,A - 2); printf(" 100\n"); } return 0;}*/int main(){ int i,n,j,k; while(1) { scanf("%d",&n); if(n==-1) break; memset(g,0,sizeof(g)); for(i=1; i<=n; i++) { scanf("%d%d",&j,&k); g[k][j]=1; } scanf("%d",&m); for(i=1; i<=m; i++) scanf("%d",&a[i]); scanf("%d",&A); init(); memset(vis,0,sizeof(vis)); DP(1,A-2); // printf("max=%d\n",dp[1][A-2]); printf("%d",A); printf(" 1"); print_path(1,A-2); printf(" 100\n"); } return 0;}
0 0
- uva10558
- uva10558(DP)
- UVA10558- A Brief Gerrymander
- C语言的精髓-指针
- OpenJudge百炼习题解答(C++)--题2690:首字母大写
- 冒泡排序--BubbleSort
- 九度OJ 1541-1550(7/10)
- 解码和编码
- uva10558
- Python基础--快速改造:字符串
- OS X从系统自带python改为Homebrew版python
- java中字符串倒序加逗号输出
- 使它读入被include语句修饰的一个文件并且输出这个文件
- 【BZOJ3339】Rmq Problem【离线】【线段树】【mex】
- Xcode清除缓存,清理多余证书
- 我的第一次上机实验1-3
- LeetCode93—Restore IP Addresses