srm575_div1&2_1000(网络流)

题意:给你一个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][N];
	bool cell[20][N],board[20][N];
	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[N],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[N],gap[N],cur[N],aug[N],path[N];
    //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();
}



猜你喜欢

转载自blog.csdn.net/shiqi_614/article/details/8869638