您的位置:首页 > 理论基础 > 计算机网络

srm575_div1&2_1000(网络流)

2013-04-30 14:46 501 查看
题意:给你一个N*M的矩阵,矩阵上的空位用'.'表示,非空位'X'表示。用L型的东西放进矩阵里,问最多能放多少个。

每个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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: