NOJ2214题目解题笔记
来源:互联网 发布:知乎和知网 编辑:程序博客网 时间:2024/06/03 16:17
原题链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2214
比赛描述
MiaoMiao和Bird喜欢一起看电视,他们都有一些近视。
有次他们看电视的时候,Bird的眼镜一不小心掉到地上,这下Bird看到电视画面都变模糊了。确切来说,我们把电视上的像素分成两种,用.表示空白区域,用*表示有颜色区域。
电视的画面为n*m的像素矩阵,对于每一个MiaoMiao看到的有色像素*,Bird都会看成
.*.
***
.*.
模糊的方块会相互重叠,可能会使原本空白区域看起来像有颜色的区域。
现在给出Bird看到的电视画面,请你求出MiaoMiao看到的电视画面中有颜色像素的最小值。
输入
第一行两个正整数n(1 ≤ n ≤ 8)和m(1 ≤ m ≤ 8)
接下来有n行,每一行有m个字符('.'或'*')。
输出
输出一个整数,表示MiaoMiao可能看到的有颜色像素数量的最小值,如果Bird看到的情况不存在,则输出-1。
样例输入
3 3
.*.
***
.*.
样例输出
1
题目来源
MoliH
动态规划。
我没有找到什么高效的解法,复杂度n*4^m(如果m>n,可以把整个电视屏幕转置,变成m*4^n),但是所幸n,m都很小。
首先对于每一行每个点是否有像素点的选择会受到上一行的影响。
int flagarray[]记录每个点上一行对应点情况。
flagarray[i]=0 上一行i处为空
flagarray[i]=1上一行i处看到是像素点并且周围没有真正的像素点
flagarray[i]=2上一行i处看到是像素点并且周围有真正的像素点
flagarray[i]=3上一行i处为真正像素点
当flagarray[i]=1,那么这一行的i处必须为真正的像素点,否则,上一行i处看到的就是空白了。
当flagarray[i]=0,那么这一行的i处必须不为真正的像素点,否则,上一行i处看到的就是像素点了。
当flagarray[i]=2,这一行i出可以有真正的像素点。
当flagarray[i]=3,这一行i处以及周围可以不必在放置真正像素点。
当第i行的flagarray[]已经确定的情况下,那么从第i行到最后一行的所有结果已经是一个确定值了。
不妨定义dp[i][flag],记录在第i行flagarray下,从i到n-1行的真正像素点数量。(flag=flagarray[0]+flagarray[1]*4+flagarray[2]*4^2+...)
每一行flag的所有可能性最多为4^m,n行一共n*4^m。
以下为代码
#include <iostream>#include <stdio.h>#include <algorithm>#include <stdlib.h>#include <string.h>#include <queue>#include <math.h>using namespace std;int p[8][8];int dp[8][65536];int n;int m;int m2;int ercifang[]= {1,2,4,8,16,32,64,128};//#define debug 0int get1s(int value){ int res=0; while(value) { if(value&1) res++; value>>=1; } return res;}//flagarray[i] 0 上一行i处为空 1上一行i处为未覆盖点 2上一行i处为覆盖点 3上一行i处为像素中心点int testvalueflag(int line,int value,int flagarray[]){ for(int i=0; i<m; i++) { if(flagarray[i]==0&&(value&ercifang[i])) return 0; if(flagarray[i]==1&&((value&ercifang[i])==0)) return 0; if(p[line][i]==0) { if(i>=1&&(value&ercifang[i-1])) return 0; if(i<m-1&&(value&ercifang[i+1])) return 0; if(value&ercifang[i]) return 0; if(flagarray[i]==3) return 0; } else if(line==n-1) { if(i>=1&&(value&ercifang[i-1])) continue; if(i<m-1&&(value&ercifang[i+1])) continue; if(value&ercifang[i]) continue; if(flagarray[i]==3) continue; return 0; } } return 1;}int run(int line,int flag){ if(dp[line][flag]>=0) return dp[line][flag]; int res=1000000;#ifdef debug int lastvaluearray[8];#endif int flagarray[8]; int flagcopy=flag; memset(flagarray,0,8*sizeof(int)); for(int i=0; i<8; i++) { flagarray[i]=flagcopy&3; flagcopy>>=2; } for(int value=0; value<m2; value++) { if(testvalueflag(line,value,flagarray)) { int rest; if(line==n-1) rest=0; else { int nextflagarraay[8]; memset(nextflagarraay,0,8*sizeof(int)); //flag 0 上一行此处为空 1上一行此处为未覆盖点 2上一行此处为覆盖点 3上一行此处为像素中心点 for(int i=0; i<m; i++) { if(p[line][i]==0) nextflagarraay[i]=0; else { if(value&ercifang[i]) nextflagarraay[i]=3; else if(flagarray[i]==3) nextflagarraay[i]=2; else if(i>=1&&(value&ercifang[i-1])) nextflagarraay[i]=2; else if(i<m-1&&(value&ercifang[i+1])) nextflagarraay[i]=2; else nextflagarraay[i]=1; } } int nextflag=0; for(int i=m-1; i>=0; i--) { nextflag<<=2; nextflag|=nextflagarraay[i]; } rest=run(line+1,nextflag); } int thisline=get1s(value); if(res>rest+thisline) {#ifdef debug int valuecopy=value; memset(lastvaluearray,0,8*sizeof(int)); for(int i=0; i<8; i++) { lastvaluearray[i]=valuecopy%2; valuecopy/=2; }#endif res=rest+thisline; } } } dp[line][flag]=res;#ifdef debug cout<<"line"<<line<<"\nflag:"; for(int i=0; i<8; i++) cout<<flagarray[i]<<' '; cout<<endl; cout<<"value"; for(int i=0; i<8; i++) cout<<lastvaluearray[i]<<' '; cout<<endl<<"res"<<res<<endl;#endif return res;}int main(){#ifdef debug freopen("in.txt","r",stdin);#endif cin>>n>>m; memset(dp,0xff,8*65536*sizeof(int)); for(int i=0; i<n; i++) { char str[10]; scanf("%s",str); for(int j=0; j<m; j++) { if(str[j]=='.') p[i][j]=0; else p[i][j]=1; } } if(n<m) { for(int i=0; i<8; i++) for(int j=0; j<i; j++) swap(p[i][j],p[j][i]); swap(n,m); } m2=pow(2,m); //43686=2+2*4+2*4^2+...+2*4^7 int ans=run(0,43690); if(ans>64) printf("-1"); else printf("%d",ans); return 0;}
- NOJ2214题目解题笔记
- 数学题目解题报告
- 数学题目解题报告
- acm题目解题思路
- java 趣味题目解题。
- 菜鸟写给菜鸟的 ——LeetCode解题笔记 Easy-题目1:292. Nim Game
- 菜鸟写给菜鸟的 ——LeetCode解题笔记 Easy-题目2:258. Add Digits
- C语言经典题目及解题思路
- [汇总]字符串题目推荐及解题报告
- 顶嵌杯初赛题目的解题报告
- 汇总]搜索题目推荐及解题报告
- [汇总]字符串题目推荐及解题报告
- POJ1207解题报告----极水的题目
- [汇总]字符串题目推荐及解题报告
- 搜索题目推荐及解题报告(转)
- 字符串题目推荐及解题报告
- 搜索题目推荐及解题报告
- 搜索题目推荐及解题报告
- 三种重要哈希介绍
- SVM入门(八)松弛变量
- 一个页面实现多个管理页面任意切换
- (hdu 2973 YAPTCHA) <数论—威尔逊定理>
- SVM入门(九)松弛变量(续)
- NOJ2214题目解题笔记
- 免费的论文查重网站
- adb shell am broadcast发送广播通知
- 简单DP
- SVM入门(十)将SVM用于多类分类
- Which are in?
- JAVA实现redis超时失效key 的监听触发
- springboot下使用JdbcTemplate和MongoTemplate链接多个mongodb源+sql源
- html非文本只显示一行,多余隐藏的实现