[BZOJ1066][SCOI2007]蜥蜴(最大流)
2016-03-07 21:44
441 查看
题目描述
传送门题解
对于每根石柱,采取一分为二的想法,即把一个点分为两个点(可抽象为石柱底部到顶部),其连线容量限制为石柱高度。s与所有有蜥蜴的点相连,容量为1。
地图内所有能跳出的点相连与t,容量为inf。
对于地图内任意两个石柱,如果间距小于d,就将其中一根石柱的顶部与另一根石柱的底部相连,其连线容量为inf。
构图完成,剩下就是跑一遍最大流,然后用蜥蜴数量减去最大流就是最终结果。
刚开始写的代码是错误的,是建图建反了。思考一下为什么错了:要搞清楚到底哪些连线是限制走的次数的,哪些连线只是表示一种可以走的关系。
代码
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int max_r=25; const int max_c=25; const int max_cnt=max_r*max_c; const int max_n=max_cnt*2+2; const int max_m=max_cnt*max_cnt+max_cnt*2; const int max_e=max_m*2; const int inf=1e9; char ch;int x; int r,c,d,x1,x2,y1,y2,cnt,n,sum,maxflow; int point[max_n],next[max_e],v[max_e],remain[max_e],tot; int number[max_r][max_c]; struct hp{ int x,y,val; }p[max_cnt]; int deep[max_n],cur[max_n],last[max_n],num[max_n]; queue <int> q; inline void add(int x,int y,int cap){ ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap; ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; } inline void bfs(int t){ for (int i=1;i<=n;++i) deep[i]=n; deep[t]=0; for (int i=1;i<=n;++i) cur[i]=point[i]; while (!q.empty()) q.pop(); q.push(t); while (!q.empty()){ int now=q.front(); q.pop(); for (int i=point[now];i!=-1;i=next[i]) if (deep[v[i]]==n&&remain[i^1]){ deep[v[i]]=deep[now]+1; q.push(v[i]); } } } inline int addflow(int s,int t){ int ans=inf,now=t; while (now!=s){ ans=min(ans,remain[last[now]]); now=v[last[now]^1]; } now=t; while (now!=s){ remain[last[now]]-=ans; remain[last[now]^1]+=ans; now=v[last[now]^1]; } return ans; } inline void isap(int s,int t){ bfs(t); for (int i=1;i<=n;++i) num[deep[i]]++; int now=s; while (deep[s]<n){ if (now==t){ maxflow+=addflow(s,t); now=s; } bool has_find=false; for (int i=cur[now];i!=-1;i=next[i]) if (deep[v[i]]+1==deep[now]&&remain[i]){ has_find=true; cur[now]=i; last[v[i]]=i; now=v[i]; break; } if (!has_find){ int minn=n-1; for (int i=point[now];i!=-1;i=next[i]) if (remain[i]) minn=min(minn,deep[v[i]]); if (!(--num[deep[now]])) break; num[deep[now]=minn+1]++; cur[now]=point[now]; if (now!=s) now=v[last[now]^1]; } } } int main(){ tot=-1; memset(point,-1,sizeof(point)); memset(next,-1,sizeof(next)); maxflow=0; scanf("%d%d%d",&r,&c,&d); for (int i=1;i<=r;++i) for (int j=1;j<=c;++j){ cin>>ch; x=ch-'0'; if (x){ p[++cnt].x=i; p[cnt].y=j; p[cnt].val=x; number[i][j]=cnt; } } //build up n=cnt*2+2; //如果可以一步跳到格子之外,那么把它向汇点连一条边,容量为inf for (int i=1;i<=cnt;++i) if (p[i].x<=d||p[i].y<=d||p[i].x>=r-d+1||p[i].y>=c-d+1) add(1+cnt+i,n,inf); //如果这里有蜥蜴,那么从源点向它连一条边,容量为1 for (int i=1;i<=r;++i) for (int j=1;j<=c;++j){ cin>>ch; if (ch=='L') add(1,1+number[i][j],1),sum++; } //其他的点两两之间连边,容量为inf for (int i=1;i<=cnt;++i) for (int j=1;j<=cnt;++j) if (i!=j){ x1=p[i].x; y1=p[i].y; x2=p[j].x; y2=p[j].y; if ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=d*d) add(1+cnt+number[x1][y1],1+number[x2][y2],inf); } //向自己连边,容量为高度 for (int i=1;i<=cnt;++i) add(1+i,1+cnt+i,p[i].val); isap(1,n); printf("%d\n",sum-maxflow); }
相关文章推荐
- ansible<2>
- 算法补习-第七天-线性表(上)
- 详解Dagger2
- IOS学习 scrollView,pageControl,tableView在同一页面上处理
- 绝对水题(一些没有被穷举遗忘的角落)
- 3.C语言常用运算符
- HTML5中的标签
- Gym 100231D Balloons 贪心
- 基本数据类型-保装类型-string三种数据类型的转换
- Ui——创建视图的方法及过程
- Android控件第2类——ImageView
- C语言中extern的用法
- Lecture 1 : the geometry of linear equati 4000 ons
- 指针的新理解
- 为什么写博客
- Android中优化ListView的ViewHolder模式
- 自我介绍
- bzoj2096: [Poi2010]Pilots
- Java多线程
- 和安全有关的那些事(非对称加密、数字摘要、数字签名、数字证书、SSL、HTTPS及其他)