[luogu]P2825 [HEOI2016/TJOI2016]游戏

本文探讨了在含有硬石头和软石头的地图上放置炸弹的问题,目标是最大化炸弹数量。通过将地图划分为由硬石头界定的区块,采用网络流算法进行二分图匹配,实现最优放置策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:P2825 [HEOI2016/TJOI2016]游戏

题意

就是在一张图上放炸弹,炸弹占领横纵一行一列。

炸弹不能穿透硬石头,软硬石头上都不能放炸弹。

求最多能放几个炸弹。

 

分析

(第一道没看题解AC的网络流)

感觉跟这道题有点像啊。。

P1129 [ZJOI2007]矩阵游戏

如果没有硬石头的限制,这道题就是要求行和列的匹配。

如果加了硬石头怎么办?

一个位置,它能覆盖到的行应该是往上下一直延伸到硬石头,往左右一直延伸到硬石头。

我们可以把行和列重分块(长或宽为$1$),一个块内只能有空格和软石头,然后就是块和块的匹配了。

一个位置可以匹配它横向和纵向的两个块,我们从横向往纵向连边。

然后源点向所有的横向连边,所有的纵向往汇点连边,跑一遍网络流版二分图匹配就可以了。

 

代码

  1 #include <bits/stdc++.h>
  2 #define ll long long
  3 #define Mid ((l+r)>>1)
  4 #define ull unsigned long long
  5 using namespace std;
  6 const int N=59,M=1e5+1009;
  7 int read(){
  8     char c;int num,f=1;
  9     while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
 10     while(c=getchar(), isdigit(c))num=num*10+c-'0';
 11     return f*num;
 12 }
 13 int readc(){
 14     char c=getchar();
 15     while(c!='#'&&c!='*'&&c!='x')c=getchar();
 16     if(c=='#')return 2;
 17     if(c=='*')return 1;
 18     if(c=='x')return 0;
 19 }
 20 int n,m,g[N][N],cnt1,cnt2;
 21 int L[N][N],R[N][N],dis[M],s,t;
 22 int head[M],nxt[M],ver[M],edge[M],tot=1;
 23 queue<int>q;
 24 void add_edge(int u,int v,int w){
 25     //cout<<u<<" "<<v<<endl;
 26     ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;edge[tot]=w;
 27     ver[++tot]=u;nxt[tot]=head[v];head[v]=tot;edge[tot]=0;
 28 }
 29 bool bfs(){
 30     while(q.size())q.pop();q.push(s);
 31     memset(dis,0,sizeof(dis));dis[s]=1;
 32     while(q.size()){
 33         int x=q.front();q.pop();
 34         for(int i=head[x];i;i=nxt[i]){
 35             if(dis[ver[i]]||!edge[i])continue;
 36             dis[ver[i]]=dis[x]+1;
 37             q.push(ver[i]);
 38             if(ver[i]==t)return 1;
 39         }
 40     }
 41     return 0;
 42 }
 43 int dinic(int x,int flow){
 44     if(x==t)return flow;
 45     int res=flow,y,k;
 46     for(int i=head[x];i&&res;i=nxt[i]){
 47         y=ver[i];
 48         if(dis[y]!=dis[x]+1||!edge[i])continue;
 49         k=dinic(y,min(res,edge[i]));
 50         if(!t)dis[y]=0;
 51         edge[i]-=k;edge[i^1]+=k;
 52         res-=k;
 53     }
 54     return flow-res;
 55 }
 56 int main()
 57 {
 58     //freopen("4.in","r",stdin);
 59     //freopen("data.out","w",stdout);
 60     n=read();m=read();
 61     for(int i=1;i<=n;i++)
 62         for(int j=1;j<=m;j++)
 63             g[i][j]=readc();
 64     for(int i=1;i<=n;i++){
 65         for(int j=1;j<=m;j++){
 66             if(g[i][j]==2||L[i][j])continue;
 67             cnt1++;
 68             for(int k=j;k<=m&&g[i][k]!=2;k++)
 69                 L[i][k]=cnt1;
 70         }
 71     }
 72     int t1=cnt1;
 73     //编号行 
 74     /*
 75     cout<<endl;
 76     for(int i=1;i<=n;i++){
 77         for(int j=1;j<=m;j++)
 78             cout<<L[i][j]<<" ";
 79         cout<<endl;
 80     }
 81     cout<<endl;
 82     */
 83     for(int j=1;j<=m;j++){
 84         for(int i=1;i<=n;i++){
 85             if(g[i][j]==2||R[i][j])continue;
 86             cnt1++;
 87             for(int k=i;k<=n&&g[k][j]!=2;k++)
 88                 R[k][j]=cnt1;
 89         }
 90     }
 91     //编号列
 92     /*
 93      cout<<endl;
 94     for(int i=1;i<=n;i++){
 95         for(int j=1;j<=m;j++)
 96             cout<<R[i][j]<<" ";
 97         cout<<endl;
 98     }
 99     cout<<endl;
100     */
101     //重标号
102     s=cnt1+11;t=cnt1+15;
103     for(int i=1;i<=t1;i++)
104         add_edge(s,i,1);
105     for(int i=t1+1;i<=cnt1;i++)
106         add_edge(i,t,1);
107     for(int i=1;i<=n;i++)
108         for(int j=1;j<=m;j++){
109             //横号竖向连接
110             if(g[i][j]!=1)continue;
111             //cout<<L[i][j]<<" "<<R[i][j]<<endl;
112             add_edge(L[i][j],R[i][j],1);
113         }
114     //连边
115     /*
116     for(int i=head[7];i;i=nxt[i])
117         cout<<ver[i]<<" ";
118     cout<<endl;
119     */
120     int maxflow=0,flow;
121     while(bfs())while(flow=dinic(s,(1<<31)-1))maxflow+=flow;    
122     printf("%d\n",maxflow); 
123     return 0;
124 }
125 /*
126 由于有硬石头和软石头,就不能当做普通的二分图匹配跑了
127 对于一个石头分隔开的一段,我们完全可以把它当成两段匹配
128 可以匹配的行数和列数不一样
129 具体来说,可以按照硬石头的位置,把一段行和一段列拆开,重标号
130 软石头是不能放的
131 所以在连边的时候注意 
132 然后跑匹配就可以了。
133 
134 */ 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146  
View Code

 

转载于:https://www.cnblogs.com/onglublog/p/10388207.html

《餐馆点餐管理系统——基于Java和MySQL的课程设计解析》 在信息技术日益发达的今天,餐饮行业的数字化管理已经成为一种趋势。本次课程设计的主题是“餐馆点餐管理系统”,它结合了编程语言Java和数据库管理系统MySQL,旨在帮助初学者理解如何构建一个实际的、具有基本功能的餐饮管理软件。下面,我们将深入探讨这个系统的实现细节及其所涉及的关键知识点。 我们要关注的是数据库设计。在“res_db.sql”文件中,我们可以看到数据库的结构,可能包括菜品表、订单表、顾客信息表等。在MySQL中,我们需要创建这些表格并定义相应的字段,如菜品ID、名称、价格、库存等。此外,还要设置主键、外键来保证数据的一致性和完整性。例如,菜品ID作为主键,确保每个菜品的唯一性;订单表中的顾客ID和菜品ID则作为外键,与顾客信息表和菜品表关联,形成数据间的联系。 接下来,我们来看Java部分。在这个系统中,Java主要负责前端界面的展示和后端逻辑的处理。使用Java Swing或JavaFX库可以创建用户友好的图形用户界面(GUI),让顾客能够方便地浏览菜单、下单。同时,Java还负责与MySQL数据库进行交互,通过JDBC(Java Database Connectivity)API实现数据的增删查改操作。在程序中,我们需要编写SQL语句,比如INSERT用于添加新的菜品信息,SELECT用于查询所有菜品,UPDATE用于更新菜品的价格,DELETE用于删除不再提供的菜品。 在系统设计中,我们还需要考虑一些关键功能的实现。例如,“新增菜品和价格”的功能,需要用户输入菜品信息,然后通过Java程序将这些信息存储到数据库中。在显示所有菜品的功能上,程序需要从数据库获取所有菜品数据,然后在界面上动态生成列表或者表格展示。同时,为了提高用户体验,可能还需要实现搜索和排序功能,允许用户根据菜品名称或价格进行筛选。 另外,安全性也是系统设计的重要一环。在连接数据库时,要避免SQL注入攻击,可以通过预编译的PreparedStatement对象来执行SQL命令。对于用户输入的数据,需要进行验证和过滤,防止非法字符和异常值。 这个“餐馆点餐管理系统”项目涵盖了Java编程、数据库设计与管理、用户界面设计等多个方面,是一个很好的学习实践平台。通过这个项目,初学者不仅可以提升编程技能,还能对数据库管理和软件工程有更深入的理解。在实际开发过程中,还会遇到调试、测试、优化等挑战,这些都是成长为专业开发者不可或缺的经验积累
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值