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,转载请注明来源
  • 相关阅读:
    解决ListView异步加载数据之后不能点击的问题
    android点击实现图片放大缩小 java技术博客
    关于 数据文件自增长 的一点理解
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Linux 超级用户的权利
    RAC 实例 迁移到 单实例 使用导出导入
    Shell 基本语法
    Linux 开机引导与关机过程
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Oracle RAC + Data Guard 环境搭建
  • 原文地址:https://www.cnblogs.com/zhber/p/4036043.html
Copyright © 2011-2022 走看看