zoukankan      html  css  js  c++  java
  • bzoj2150 部落战争

    Description

    lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土。 A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住。lanzerb把自己的部落分成若干支军队,他们约定: 1. 每支军队可以从任意一个城镇出发,并只能从上往向下征战,不能回头。途中只能经过城镇,不能经过高山深涧。 2. 如果某个城镇被某支军队到过,则其他军队不能再去那个城镇了。 3. 每支军队都可以在任意一个城镇停止征战。 4. 所有军队都很奇怪,他们走的方法有点像国际象棋中的马。不过马每次只能走1*2的路线,而他们只能走R*C的路线。 lanzerb的野心使得他的目标是统一全国,但是兵力的限制使得他们在配备人手时力不从心。假设他们每支军队都能顺利占领这支军队经过的所有城镇,请你帮lanzerb算算至少要多少支军队才能完成统一全国的大业。

    Input

    第一行包含4个整数M、N、R、C,意义见问题描述。接下来M行每行一个长度为N的字符串。如果某个字符是'.',表示这个地方是城镇;如果这个字符时'x',表示这个地方是高山深涧。

    Output

    输出一个整数,表示最少的军队个数。

    Sample Input

    【样例输入一】
    3 3 1 2
    ...
    .x.
    ...
    【样例输入二】
    5 4 1 1
    ....
    ..x.
    ...x
    ....
    x...

    Sample Output

    【样例输出一】
    4

    【样例输出二】
    5
    【样例说明】

    【数据范围】
    100%的数据中,1<=M,N<=50,1<=R,C<=10。

    从题意中很容易看出这是最小路径覆盖……因为从任意点出发到任意点停止,而且没有环

    第一次做最小路径覆盖。自己yy了一下,应该要拆点。后来无论怎么连边也没法搞。

    比如我要这样连:(图中所有边容量为1)

    那么我要使1和1‘,2和2’,3和3‘之间的边保证满流,代表全图都已经覆盖,然后S到T的最大流尽量小。这好像可以用有上下界的网络流搞定,但是太麻烦了

    去百度了一下,结果发现其实把它拆点搞成二分图,然后互相连边求最大匹配,那么tot-ans就是答案。我原来一直想着用最大流表示答案,然后各种斯巴达……

    我觉得这还是很好理解的。最坏情况下覆盖全图需要n次,每次只覆盖一个点,现在最大匹配中两个点i,j匹配,代表有两个点可以缩成一个点,就是覆盖了i之后可以直接接着覆盖j,,所以答案-1。

    #include<cstdio>
    #include<cstring>
    #define S 0
    #define T 55555
    #define inf 0x7fffffff
    struct edge{
    	int to,next,v;
    }e[100001];
    int n,m,r,c,cnt=1,ans,tot;
    int head[100001];
    int h[100001];
    int q[100001];
    bool mrk[60][60];
    inline int min(int a,int b)
    {return a<b?a:b;}
    inline void ins(int u,int v,int w)
    {
    	e[++cnt].to=v;
    	e[cnt].v=w;
    	e[cnt].next=head[u];
    	head[u]=cnt;
    }
    inline void insert(int u,int v,int w)
    {
    	ins(u,v,w);
    	ins(v,u,0);
    }
    inline bool bfs()
    {
    	memset(h,-1,sizeof(h));
    	int t=0,w=1;
    	q[1]=S;h[S]=0;
    	while (t<w)
    	{
    		int now=q[++t];
    		for (int i=head[now];i;i=e[i].next)
    		  if(h[e[i].to]==-1&&e[i].v)
    		  {
    		  	q[++w]=e[i].to;
    		  	h[e[i].to]=h[now]+1;
    		  }
    	}
    	if (h[T]==-1) return 0;
    	return 1;
    }
    inline int dfs(int x,int f)
    {
    	if (x==T||!f) return f;
    	int used=0,w;
    	for (int i=head[x];i;i=e[i].next)
    	  if (e[i].v&&h[e[i].to]==h[x]+1)
    	  {
    	  	w=f-used;
    	  	w=dfs(e[i].to,min(e[i].v,w));
    	  	used+=w;
    	  	e[i].v-=w;
    	  	e[i^1].v+=w;
    	  }
    	if (!used) h[x]=-1;
    	return used;
    }
    inline void dinic()
    {while(bfs())ans+=dfs(S,inf);}
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&r,&c);
    	const int mx[4]={r,c,c,r};
    	const int my[4]={c,r,-r,-c};
    	for (int i=1;i<=n;i++)
    	  for (int j=1;j<=m;j++)
    	    {
    	    	char ch=getchar();
    	    	while (ch!='.'&&ch!='x')ch=getchar();
    	    	if (ch=='.')
    			{
    				mrk[i][j]=1;
    				tot++;
    			}
    	    }
    	for (int i=1;i<=n;i++)
    	  for (int j=1;j<=m;j++)
    	  	if (mrk[i][j])
    	  	{
    	  		insert(S,(i-1)*m+j,1);
    	    	insert((i-1+n)*m+j,T,1);
    	    	for (int k=0;k<4;k++)
    	    	  {
    	    	  	int nx=mx[k]+i;
    	    	  	int ny=my[k]+j;
    	    	  	if (r==c&&k%2) continue;
    	    	  	if (nx>=1&&nx<=n&&ny>=1&&ny<=m&&mrk[nx][ny])
    	    	  	  insert((i-1)*m+j,(nx-1+n)*m+ny,1);
    	    	  }
    	  	}
    	dinic();
    	printf("%d
    ",tot-ans);
    }



    ——by zhber,转载请注明来源
  • 相关阅读:
    webpack-dev-server
    python 基础语言 学习笔记
    react 避免重复渲染
    获取cookie
    解决 canvas 在高清屏中绘制模糊的问题
    h5页面点击事件ios没反应 移动端兼容性问题
    rem 刷新闪烁问题
    谷歌禁止input自动填充表单信息
    react 循环产生定时器
    IOS开发-UI学习-UIWebView,简单浏览器的制作
  • 原文地址:https://www.cnblogs.com/zhber/p/4036043.html
Copyright © 2011-2022 走看看