棋盘 (省队集训 网(du)络(liu)流(ti))
来源:互联网 发布:淘宝代销怎么没有了 编辑:程序博客网 时间:2024/05/18 15:05
给定一个 n * n 的棋盘,棋盘上每个位置要么为空要么为障碍。定义
棋盘上两个位置 (x,y)和(u, v) 能互相攻击当前仅当满足以下两个条件:
• x = u 或 y = v
• 对于 (x; y) 与 (u; v) 之间的所有位置,均不是障碍。
现在有 q 个询问,每个询问给定 ki,要求从棋盘中选出 ki 个空位置来放棋子,问最少互相能攻击到的棋子对数是多少?
输入格式
第一行一个整数 n。
接下来输入一个 n * n 的字符矩阵,一个位置若为.,则表示这是一个
空位置,若为 #,则为障碍。
第 n + 2 行输入一个整数 q 代表询问个数。
接下来 q 行,每行一个整数 k,代表要放的棋子个数。
输出格式
输出共 q 行,每行代表对应询问的最少的互相能攻击到的棋子对数。
样例数据一
chess.in
4 2
. . # .
# # # #
. . # .
. . # .
1
7
chess.out
2
分析:
这道题采用了缩点的思路:把每一个非障碍点相连的横向点缩成一个点,相连的纵向点缩成一个点,
在网络流建图中,横向点作为x部,纵向点作为y部,
每一个横向点向与ta有交集的横向点连一条流量是1,费用是0的边,
每一个横向点包含几(n)个点,就从源点向其连多少(n)条流量是1,费用分别是(0,1,2,3…n),
对于每个纵向点也如此处理(只不过是向汇点连边),
之后跑一个最小费用最大流,记录每次增广的费用(ans[i]),这样在询问时直接输出就好了
看图理解一下:
这里写代码片#include<cstdio>#include<iostream>#include<cstring>#include<queue>using namespace std;const int INF=0x33333333;int n,q;int map1[55][55],map2[55][55],maxx=0;struct node{ int x,y,nxt,v,c;};node way[250010];int st[250000],tot=-1,s,t,pre[30000],p[30000],d[30000],ans[30000];void add(int u,int w,int z,int co){ tot++; way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];way[tot].c=co;st[u]=tot; tot++;way[tot].x=w;way[tot].y=u;way[tot].v=0;way[tot].nxt=st[w];st[w]=tot;way[tot].c=-co;}void lianbian(){ s=0; t=29999; int i,j,k,blo=0; int tt=0; for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (map1[i][j]==0) { blo=0; tt++; int f1=j; while (f1<=n&&map1[i][f1]==0) { map1[i][f1]=tt; add(s,tt,1,blo); blo++; f1++; } } for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (map2[i][j]==0) { blo=0; tt++; int f1=i; while (f1<=n&&map2[f1][j]==0) { map2[f1][j]=tt; add(map1[f1][j],tt,1,0); add(tt,t,1,blo); blo++; f1++; } } return;}int spfa(){ int i; memset(pre,0,sizeof(pre)); memset(p,1,sizeof(p)); memset(d,0x33,sizeof(d)); //花费 queue<int> q; q.push(s); d[s]=0; p[s]=0; while (!q.empty()) { int r=q.front(); q.pop(); for (i=st[r];i!=-1;i=way[i].nxt) { if (way[i].v&&d[way[i].y]>d[r]+way[i].c) //这条路可走而且有修改价值 { d[way[i].y]=d[r]+way[i].c; pre[way[i].y]=i; //修改来自哪条边 if (p[way[i].y]) { p[way[i].y]=0; q.push(way[i].y); } } } p[r]=1; } return d[t]<INF;}int doit(){ int an=0,sum,i,j=0; while (spfa()) { sum=INF; for (i=t;i!=s;i=way[pre[i]].x) //从汇点检索一下是通过哪条最小费用增广路 sum=min(sum,way[pre[i]].v); //pre:以i为终点的边的编号 an+=d[t]*sum; for (i=t;i!=s;i=way[pre[i]].x) { way[pre[i]].v-=sum; way[pre[i]^1].v+=sum; } ans[++j]=an; }}int main(){ //freopen("chess.in","r",stdin); //freopen("chess.out","w",stdout); memset(st,-1,sizeof(st)); scanf("%d",&n); for (int i=1;i<=n;i++) { char mm[55]; scanf("%s",&mm); for (int j=0;j<n;j++) if (mm[j]=='#') map1[i][j+1]=map2[i][j+1]=-1; } lianbian(); doit(); scanf("%d",&q); for (int i=1;i<=q;i++) { int opt; scanf("%d",&opt); printf("%d\n",ans[opt]); } return 0;}
阅读全文
0 0
- 棋盘 (省队集训 网(du)络(liu)流(ti))
- 【SDOI省队集训题】棋盘(最小费用流)
- [bzoj4930][SDOI省队集训2017]棋盘
- POJ 1321 棋盘问题(棋盘DFS)
- 最小树形图(Chu&Liu/Edmonds's algorithm)
- UVa 11218 - KTV, Rujia Liu的神题(一)
- UVa 11218 - KTV, Rujia Liu的神题(一)
- Uva 11991 - Easy Problem from Rujia Liu?(map 查找)
- uva 11991 Easy Problem from Rujia Liu?(map应用)
- UVA - 11991 - Easy Problem from Rujia Liu? (STL)
- 11991 - Easy Problem from Rujia Liu?(抽象数据结构)
- uva11991 Easy Problem from Rujia Liu?(STL)
- UVA11991 - Easy Problem from Rujia Liu?(数据结构,模拟)
- 水题(Easy Problem from Rujia Liu?,UVA 11991)
- ROS机器人操作系统入门(转载整理于TOP LIU)
- 暑假集训(bellman)
- 暑期集训(首篇博文)
- 棋盘问题(P1321)
- 多重集合的排列和组合问题
- Android自动化测试uiautomator入门
- bzoj 3622: 已经没有什么好害怕的了 dp+容斥原理
- SVM代码实现非线性分类
- VideoFrame的编码,发送流(一)
- 棋盘 (省队集训 网(du)络(liu)流(ti))
- Hadoop 学习1
- 日常训练 20160601 B君的关系 羊毛 (Wolle) Burnside
- 欢迎使用CSDN-markdown编辑器
- leetcode136题解
- 动态加载表格数据,自动增加tr td
- 2017浙工大之江学院校赛D-数学||矩阵快速幂
- Python学习笔记02-列表与操作列表
- Android应用开发之所有动画使用详解