题目链接:点击查看

题目大意:填数游戏,给出一个n*m的矩阵,矩阵中存在三种方块:

  1. 纯黑的方块:没什么用
  2. 纯白的方块:等待我们填数字的方块
  3. 黑色方块上有数字:
    1. 左下角有数字:当前黑色方块下面的白色方块内数字之和等于当前数字
    2. 右上角有数字:当前黑色方块右面的白色方块内数字之和等于当前数字

在满足上述规则的条件下,将矩阵补充完整

题目分析:因为在填写矩阵的时候,可以使用重复数字,数字的范围是1~9,所以题目相对来说还是比较简单的,稍微分析一下可以知道,对于每个白色方块,影响其内部数字的因素无非就是其最左边的黑色方块与其最上面的黑色方块,所以如果用网络流的话,我们将其互相建边就好了,因为白色方块和左边的黑色方块与上边的黑色方块有关系,换句话说,其链接了左边与上边的黑色方块,不妨从源点流出一股流量,经过向下的黑色方块后途径白色方块再经过向右的黑色方块最后流向汇点,这样跑完最大流后,因为前期在建边时对于各个地方流量的限制,我们就可以控制最大流在规定范围内了,最后跑一边残余网络就能找到答案了

有几个需要注意的细节,首先是数字的范围是1~9,而每条边的流量是可以达到0的,为了方便处理,我们可以将数值映射到流量后整体减少1,将其规定为0~8对应着1~9,最后对参与网络操作的时候记得加一就好了,然后就是这个题的数据稍微有点大,用dinic会被卡常,所以可以选择用SAP来跑最大流,其他的没什么注意的了,直接说一下具体的建边方法吧:

  1. 源点->所有向下的黑色方块,流量为其数字减去与其有关系的白色方块个数之差(因为1~9变成了0~8,所以整体减去了1)
  2. 所有向下的黑色方块->与其有关系的白色方块,流量为8
  3. 所有白色方块->与其有关系的向右的黑色方块,流量为8
  4. 所有向右的黑色方块->汇点,流量为其数字减去与其有关系的白色方块的个数之差(原理同上)

这样跑完最大流后直接对残余网络操作就好了,因为所有的黑色方块最后都是需要输出下划线的,所以对于每个白色方块,我们找一下与其有关系的向右的黑色方块的连边,用边权的残余流量就可以计算出跑最大流使用了多少流量了

代码:

#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=3e4+100;//点数的最大值const int M=2e5+100;//边数的最大值struct Node
{int from,to,next;int cap;
}edge[M];int tol,head[N],dep[N],gap[N];//gap[x]=y :说明残留网络中dep[i]==x的个数为yint nn;//n是总的点的个数,包括源点和汇点int n,m;struct Maze
{char s[8];
}maze[110][110];int mark[110][110];//记录每个白点对应的向右的黑格 int ans[110][110];void init()
{tol=0;nn=2;memset(head,-1,sizeof(head));memset(ans,-1,sizeof(ans));
}void addedge(int u,int v,int w)
{edge[tol].from=u;edge[tol].to=v;edge[tol].cap=w;edge[tol].next=head[u];head[u]=tol++;edge[tol].from=v;edge[tol].to=u;edge[tol].cap=0;edge[tol].next=head[v];head[v]=tol++;
}
void BFS(int start,int end)
{memset(dep,-1,sizeof(dep));memset(gap,0,sizeof(gap));gap[0]=1;int que[N];int front,rear;front=rear=0;dep[end]=0;que[rear++]=end;while(front!=rear){int u=que[front++];if(front==N)front=0;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(dep[v]!=-1)continue;que[rear++]=v;if(rear==N)rear=0;dep[v]=dep[u]+1;++gap[dep[v]];}}
}
int SAP(int start,int end)
{int res=0;BFS(start,end);int cur[N];int S[N];int top=0;memcpy(cur,head,sizeof(head));int u=start;int i;while(dep[start]<nn){if(u==end){int temp=inf;int inser;for(i=0;i<top;i++)if(temp>edge[S[i]].cap){temp=edge[S[i]].cap;inser=i;}for(i=0;i<top;i++){edge[S[i]].cap-=temp;edge[S[i]^1].cap+=temp;}res+=temp;top=inser;u=edge[S[top]].from;}if(u!=end&&gap[dep[u]-1]==0)//出现断层,无增广路break;for(i=cur[u];i!=-1;i=edge[i].next)if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)break;if(i!=-1){cur[u]=i;S[top++]=i;u=edge[i].to;}else{int min=nn;for(i=head[u];i!=-1;i=edge[i].next){if(edge[i].cap==0)continue;if(min>dep[edge[i].to]){min=dep[edge[i].to];cur[u]=i;}}--gap[dep[u]];dep[u]=min+1;++gap[dep[u]];if(u!=start)u=edge[S[--top]].from;}}return res;
}int get_id(int x,int y,int k)//k=0:向下 k=1:向右 k=2:空白格
{return (x-1)*m+y+k*n*m;
}bool check(int x,int y)//判断(x,y)是否为空白格
{if(x<=0||y<=0||x>n||y>m)return false;return maze[x][y].s[0]=='.';
}int get_num(char s[],int st)//得到点(x,y)的数字,st代表着起始位置,0代表第一个数,4代表第二个数
{int ans=0;for(int i=st;i<st+3;i++)ans=ans*10+s[i]-'0';return ans;
}int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);while(scanf("%d%d",&n,&m)!=EOF){init();for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%s",&maze[i][j].s);int st=N-1,ed=st-1;//源点->向下的黑点->空白格->向右的黑点->汇点 for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(check(i,j)){nn++;continue;}if(maze[i][j].s[0]!='X')//向下 {nn++;int sum=0;int xx=i+1,yy=j;while(check(xx,yy)){addedge(get_id(i,j,0),get_id(xx,yy,2),8);//向下的黑格->空白格 sum++;xx++;}addedge(st,get_id(i,j,0),get_num(maze[i][j].s,0)-sum);//源点->向下的黑格 }if(maze[i][j].s[4]!='X')//向右 {nn++;int sum=0;int xx=i,yy=j+1;while(check(xx,yy)){mark[xx][yy]=get_id(i,j,1);addedge(get_id(xx,yy,2),get_id(i,j,1),8);//空白格->向右的黑格 sum++;yy++; }addedge(get_id(i,j,1),ed,get_num(maze[i][j].s,4)-sum);//向右的黑格->汇点 }}}SAP(st,ed);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(maze[i][j].s[0]=='.'){int u=get_id(i,j,2);for(int k=head[u];k!=-1;k=edge[k].next){if(edge[k].to==mark[i][j])//找到了之前建的边,根据残余流量计算答案{ans[i][j]=9-edge[k].cap;}}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(ans[i][j]==-1)printf("_ ");elseprintf("%d ",ans[i][j]);}printf("\n");}} return 0;
}

HDU - 3338 Kakuro Extension(最大流+思维建边)相关推荐

  1. HDU 3338 Kakuro Extension

    Kakuro Extension 题意:现在有一个n*m的矩形,现在每个白色的点都可以填 [1, 9] 中的一个数字.现在要求每行加起来的值等于左边的那个黑块的右值,每列加起来等于上边那个黑块的左值, ...

  2. HDU - 2732 Leapin' Lizards(最大流+思维建边)

    题目链接:点击查看 题目大意:给出两个n*m的迷宫,第一个迷宫中表示每个柱子的耐久度,第二个迷宫表示的是每一只蜥蜴的位置,现在给出每只蜥蜴可以跳跃的最大曼哈顿距离,规定跳出迷宫边界就可以逃离迷宫,现在 ...

  3. HDU3338 Kakuro Extension(最大流+思维构图)

    这道题一定要写一下,卡了好久. 题意: 有黑白两种方格,最上边一行和最左边一列一定是黑色,然后其余的地方有可能是黑色,有可能是白色,和白色相邻的黑色方格里有数字(1个或2个), 现在要求在白色方格里填 ...

  4. HDU Problem - 3338 Kakuro Extension (最大流,建图)

    题目链接 Problem Description If you solved problem like this, forget it.Because you need to use a comple ...

  5. HDU - 4292 Food(最大流+思维建边)

    题目链接:点击查看 题目大意:作为食堂管理人,现在有n个学生需要打饭,每个学生需要一个饮料和食物才能满足,每个学生可以同时接受多种不同的食物和饮料,现在给出每种食物和饮料的个数,问最多能让多少学生满足 ...

  6. HDU - 5988 Coding Contest(最大费用最大流+思维建边)

    题目链接:点击查看 题目大意:给出n个点和m条边,每个点有ai个人和bi份食物,每条边最多能通过ci个人,以及除了第一个人之外,其他人通过每条边触电的概率为pi,在以上约束下,要求每个人都必须吃到一份 ...

  7. HDU - 3605 Escape(二分图多重匹配-网络流最大流+思维建边+状态压缩)

    题目链接:点击查看 题目大意:到世界末日了,现在人们要逃离去其他的星球,现在给出n个人以及m个星球,再给出每个人可以前往的星球,最后给出每个星球的容量,题目问最多能让多少个人逃离 题目分析:这个题读完 ...

  8. 洛谷 - P3980 [NOI2008]志愿者招募(最小费用最大流+思维建边)

    题目链接:点击查看 题目大意:现在有n天需要志愿者,每一天需要招募的人数是Ai个人,现在有m类志愿者,每类志愿者可以在[l,r]天内被招募,需要花费的代价为Ci,现在需要安排一种招募方式,可以使得总花 ...

  9. 洛谷 - P1251 餐巾计划问题(最小费用最大流+思维建边)

    题目链接:点击查看 题目大意:给出n天每天所需要的新餐巾的数量,现在有多种方式可以获得新餐巾,问如何运营能使花费最少: 直接购买,花费为cost 将脏餐巾送到快洗部,需要洗t1天,花费为c1 将脏餐巾 ...

最新文章

  1. 【NOIP2018】 游记
  2. oracle:sql查询
  3. 不要被约束的意思_不要再奢望你会变得自律了丨“他律”比“自律”更重要
  4. anaconda中怎么sh_【好工具】 深度学习炼丹,你怎么能少了这款工具!JupyterLab 远程访问指南...
  5. 开着开着,Model S天窗飞了!特斯拉回应...
  6. Qt——P20 模态和非模态对话框创建
  7. OpenCv平滑与模糊
  8. (综述,讲得很好)基于3DMM的三维人脸重建技术总结
  9. MATLAB-Control System Toolbox™0.控制系统工具箱说明
  10. Java-幸运抽奖系统(综合练习)
  11. androidstudio图片居中_android studio textView 垂直居中
  12. 腾讯云网站域名备案帮助说明文档
  13. 计算机的假桌面,如何删除桌面假Internet Explorer图标
  14. Android数据库高手秘籍(六)——LitePal的修改和删除操作
  15. 把握出租车行驶的数据脉搏 :出租车轨迹数据给你答案!
  16. 简单的命令改善你的Linux安全
  17. 学生请假管理系统(jsp+servlet)
  18. 小学计算机兴趣班培训总结,小学开展电脑制作活动工作总结
  19. 容器的作用span div10
  20. 初识html5小游戏

热门文章

  1. mysql数据库连接ado_mysql:2种连接数据库方式:ADO连接、mysql的API连接 | 学步园...
  2. Nginx使用openssl生成证书文件
  3. RabbitMQ队列持久化
  4. ObjectFactory 的create()方法什么时候被调用?
  5. MyBatis 源码解读-执行SQL
  6. Spring-Cloud中各个组件的职责
  7. 创建工程并测试RedisTemplate
  8. RocketMQ的存储之消息的同步、异步刷盘
  9. 常见问题_数组索引越界异常
  10. 制作模块-制作模块压缩包