srm575_div1&2_1000(网络流)
2013-04-30 14:46
501 查看
题意:给你一个N*M的矩阵,矩阵上的空位用'.'表示,非空位'X'表示。用L型的东西放进矩阵里,问最多能放多少个。
每个L型的物体可以随意旋转90度。
物体之间不能相互覆盖。
不能覆盖那些已经有X的格子。
每个L型的转角必须是黑色的格子。
一个格子是黑色,它的定义为,i+j是偶数 。
如果数据范围小的话,用当前列的去更新下一列的,当前列可能对应着不同的方格占据方案,那么利用位压缩去对应各种不同的占据情况,那么这就是一个DP。
如果数据范围大一点,将所有黑色的格子标记为2,剩下的格子,如果是奇数行的标记为1,否则标记为2。从超级源点向所有标记为1的点连一条容量为1的边,从所有标记为3的点向超级汇点连一条容量为1的边,然后对于每个标记为i的点向它周围标记为i+1的点连一条容量为1的边。跑最大流。
每个L型的物体可以随意旋转90度。
物体之间不能相互覆盖。
不能覆盖那些已经有X的格子。
每个L型的转角必须是黑色的格子。
一个格子是黑色,它的定义为,i+j是偶数 。
如果数据范围小的话,用当前列的去更新下一列的,当前列可能对应着不同的方格占据方案,那么利用位压缩去对应各种不同的占据情况,那么这就是一个DP。
const int N=55; string tile[][2] = { {".X", "XB"}, {"X.", "BX"}, {"BX", "X."}, {"XB", ".X"} }; class TheTilesDivTwo { public: int find(vector <string>); int dp[20] ; bool cell[20] ,board[20] ; int row,column; bool check(char chr,int i,int j) { if(chr=='.') return 1; if(cell[i][j]+board[i][j]!=0) return 0; if(chr=='B') { if((i+j)%2==0) return 1; else return 0; } return 1; } void dfs(int state,int col,int r,int cnt) { if(r==row-1) { int ns=0; for(int i=0;i<row;i++) if(cell[i][col+1]) { ns|=(1<<i); } dp[ns][col+1]=max(dp[ns][col+1],dp[state][col]+cnt); return ; } dfs(state,col,r+1,cnt); for(int t=0;t<4;t++) { bool ok=1; for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { if(check(tile[t][i][j],r+i,col+j)==0) ok=0; } } if(ok==0) continue; for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { if(tile[t][i][j]!='.') cell[r+i][col+j]=1; } } dfs(state,col,r+1,cnt+1); for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { if(tile[t][i][j]!='.') cell[r+i][col+j]=0; } } } } }; int TheTilesDivTwo::find(vector <string> board_) { row=(int)board_.size(); column=(int)board_[0].length(); memset(dp,-1,sizeof(dp)); memset(board,0,sizeof(board)); memset(cell,0,sizeof(cell)); for(int i=0;i<row;i++) { for(int j=0;j<column;j++) if(board_[i][j]=='X') { board[i][j]=1; } } dp[0][0]=0; for(int j=0;j<column;j++) { for(int i=0;i<(1<<row);i++) if(dp[i][j]!=-1) { memset(cell,0,sizeof(cell)); for(int k=0;k<row;k++) if(i&(1<<k)) cell[k][j]=1; dfs(i,j,0,0); } } int ans=0; for(int i=0;i<(1<<row);i++) ans=max(ans,dp[i][column-1]); return ans; }
如果数据范围大一点,将所有黑色的格子标记为2,剩下的格子,如果是奇数行的标记为1,否则标记为2。从超级源点向所有标记为1的点连一条容量为1的边,从所有标记为3的点向超级汇点连一条容量为1的边,然后对于每个标记为i的点向它周围标记为i+1的点连一条容量为1的边。跑最大流。
#include <iostream> #include <cstdio> #include <vector> #include <string> #include <cstring> using namespace std; const int N=100005; const int M=400005; #define INF 0x3f3f3f3f struct Edge { int u,v,flow,cap,pre; Edge(){} Edge(int u,int v,int cap,int pre) : u(u),v(v),cap(cap),pre(pre) {flow=0;} }edge[M]; int head ,tot; void addEdge(int u,int v,int cap) { edge[tot]=Edge(u,v,cap,head[u]); head[u]=tot++; edge[tot]=Edge(v,u,0,head[v]); head[v]=tot++; } void init() //添加边之前要先初始化。 { tot=0; memset(head,-1,sizeof(head)); } struct MaxFlow { int st,ed,n,mx_flow;//表示起点,终点,有多少个点,所求的最大流是多少。 int dis ,gap ,cur ,aug ,path ; //dis表示每个点的距离标记,gap表示距离为i的点有多少个,cur用于当前孤优化, //aug记录找到的增广路流量,path记录找到的增广路的路径。 void init() { for(int i=0;i<=n;i++) { aug[i]=gap[i]=dis[i]=0; cur[i]=head[i]; } aug[st]=INF; gap[0]=n; mx_flow=0; } int augment(int &point)//修改找到的增广路上的边的容量,当前点修改为起点。 { for(int i=ed;i!=st;i=edge[path[i]].u) { int pair=path[i]^1; edge[ path[i] ].flow+=aug[ed]; edge[ pair ].flow-=aug[ed]; } point=st; return aug[ed]; } int solve() { init(); int u=st; while(dis[st]<n) { if(u==ed) mx_flow+=augment(u); bool flag=1; for(int i=head[u];i!=-1;i=edge[i].pre) { int v=edge[i].v; if(edge[i].cap-edge[i].flow>0&&dis[u]==dis[v]+1) { path[v]=i; cur[u]=i; aug[v]=min(aug[u],edge[i].cap-edge[i].flow); u=v; flag=0; break; } } if(flag) { if(--gap[dis[u]]==0) return mx_flow; dis[u]=N; for(int i=head[u];i!=-1;i=edge[i].pre) { int v=edge[i].v; if(edge[i].cap-edge[i].flow>0) dis[u]=min(dis[u],dis[v]+1); } gap[dis[u]]++; cur[u]=head[u]; if(u!=st) u=edge[path[u]].u; } } return mx_flow; } }sap; const int dx[]= {0,0,1,-1}; const int dy[]= {1,-1,0,0}; class TheTilesDivOne { public: int find(vector <string>); int lab[55][55]; int in[10000],out[10000]; int n,m; int calu(int x,int y) { return x*m+y; } }; int TheTilesDivOne::find(vector <string> board_) { memset(lab,-1,sizeof(lab)); memset(in,-1,sizeof(in)); memset(out,-1,sizeof(out)); n=(int)board_.size(); m=(int)board_[0].length(); tot=0; memset(head,-1,sizeof(head)); int cnt=1; for(int i=0; i<n; i++) { for(int j=0; j<m; j++) if(board_[i][j]=='.') { in[calu(i,j)]=cnt++; out[calu(i,j)]=cnt++; addEdge(in[calu(i,j)],out[calu(i,j)],1); if((i+j)%2==0) lab[i][j]=2; else { if(i%2) lab[i][j]=1; else lab[i][j]=3; } } } int st=0,ed=cnt; for(int i=0; i<n; i++) { for(int j=0; j<m; j++) if(board_[i][j]=='.') { if(lab[i][j]==1) { addEdge(st,in[calu(i,j)],1); } if(lab[i][j]==3) { addEdge(out[calu(i,j)],ed,1); } for(int k=0; k<4; k++) { int x=i+dx[k],y=j+dy[k]; if(x>=0&&x<n&&y>=0&&y<m&&board_[x][y]=='.') { if(lab[i][j]+1==lab[x][y]) { addEdge(out[calu(i,j)],in[calu(x,y)],1); } } } } } sap.st=st; sap.ed=ed; sap.n=cnt+1; return sap.solve(); }
相关文章推荐
- Topcoder SRM 543 DIV2 1000 EllysThreeRivers & DIV1 500 EllysRivers
- srm 303 div2 1000 (简单暴力,分解素因子)
- srm 558 div1 1000 SurroundingGame(最小割构图题)
- SRM 598 DIV2 1000 FoxAndFencingEasy
- [距离限制模型 & 最小割]TopCoder SRM590 DIV1 1000. FoxAndCity
- TopCoder SRM 474 DIV1 1000
- SRM575 div1 level1
- SRM575 div1 level2
- Top Coder SRM 582 DIV2 1000
- Topcoder SRM 616 Div2 1000 TwoLLogo
- srm 306 div2 1000 (字符串dp,进阶)
- srm 299 div2 1000(强连通分量缩点,拓扑)
- TopCoder SRM 634 Div2 Problem 1000 - SpecialStrings
- SRM 575 250 DIV2
- [最小生成树] Codeforces 632F Educational Codeforces Round 9 F. Magic Matrix & SRM 687 div1 AllGraphCuts
- Topcoder SRM 636 Div2 1000(切蛋糕,最后一块给自己。最小值中求最大值,二分+枚举)
- srm 300 div2 1000(贪心进阶)
- srm 301 div2 1000 (经典dp, 括号匹配)
- Topcoder SRM 146 Div2 1000(dfs搜索,经典过桥问题,很有意思)
- Topcoder SRM 517 DIV2 1000 CuttingGrass