骑士共存问题 二分图的最大独立集

来源:互联网 发布:java数据类型取值范围 编辑:程序博客网 时间:2024/05/16 17:49

在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘
上某些方格设置了障碍,骑士不得进入。

 

对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑
士,使得它们彼此互不攻击。

第一行有2 个正整数n 和m (1<=n<=200, 0<=m<n^2),
分别表示棋盘的大小和障碍数。接下来的m 行给出障碍的位置。每行2 个正整数,表示障
碍的方格坐标。

将计算出的共存骑士数输出

3 2

1 1

3 3

5

详见试题

题目可以在这里提交:http://wikioi.com/homework/23/

分析:二分图的最大独立集,可以先求二分图的最大匹配,简单建图。

代码:

//Isap算法,复杂度O(n^2m)#pragma comment(linker,"/STACK:102400000,102400000")#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#include <vector>#include <string>#include <math.h>#include <queue>#include <stack>#include <map>#include <set>using namespace std;typedef long long ll;   //记得必要的时候改成无符号const int maxn=100005;const int maxm=1000005;const int INF=1000000000;struct EdgeNode{    int from;    int to;    int cost;    int next;}edge[maxm];int head[maxn],cnt;void add(int x,int y,int z){    edge[cnt].from=x;edge[cnt].to=y;edge[cnt].cost=z;edge[cnt].next=head[x];head[x]=cnt++;    edge[cnt].from=y;edge[cnt].to=x;edge[cnt].cost=0;edge[cnt].next=head[y];head[y]=cnt++;    //printf("%d %d %d\n",x,y,z);}void init(){    cnt=0;    memset(head,-1,sizeof(head));}int S,T,n,m;int d[maxn],gap[maxn],curedge[maxn],pre[maxn];//curedge[]为当前弧数组,pre为前驱数组int sap(int S,int T,int n)  //n为点数{    int cur_flow,flow_ans=0,u,tmp,neck,i;    memset(d,0,sizeof(d));    memset(gap,0,sizeof(gap));    memset(pre,-1,sizeof(pre));    for(i=0;i<=n;i++)curedge[i]=head[i]; //初始化当前弧为第一条邻接表    gap[0]=n;    u=S;    while(d[S]<n)             //当d[S]>=n时,网络中肯定出现了断层    {        if(u==T)        {            cur_flow=INF;            for(i=S;i!=T;i=edge[curedge[i]].to)            {                           //增广成功,寻找瓶颈边                if(cur_flow>edge[curedge[i]].cost)                {                    neck=i;                    cur_flow=edge[curedge[i]].cost;                }            }            for(i=S;i!=T;i=edge[curedge[i]].to)            {                             //修改路径上的边容量                tmp=curedge[i];                edge[tmp].cost-=cur_flow;                edge[tmp^1].cost+=cur_flow;            }            flow_ans+=cur_flow;            u=neck;                     //下次增广从瓶颈边开始        }        for(i=curedge[u];i!=-1;i=edge[i].next)            if(edge[i].cost&&d[u]==d[edge[i].to]+1)               break;        if(i!=-1)        {            curedge[u]=i;            pre[edge[i].to]=u;            u=edge[i].to;        }        else        {            if(0==--gap[d[u]])break;    //gap优化            curedge[u]=head[u];            for(tmp=n,i=head[u];i!=-1;i=edge[i].next)                if(edge[i].cost)                   tmp=min(tmp,d[edge[i].to]);            d[u]=tmp+1;            ++gap[d[u]];            if(u!=S)u=pre[u];           //重标号并且从当前点前驱重新增广        }    }    return flow_ans;}bool mp[205][205];int dis[9][3]={{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2}};int yj(int x,int y){    if(x<1||x>n||y<1||y>n)return 1;    return 0;}int build(){    int i,j,k,x,y,a,b,s=0;    for(i=1;i<=n;i++){        for(j=1;j<=n;j++){            if(mp[i][j])continue;            s++;            a=(i-1)*n+j;            add(S,a,1);            add(a+n*n,T,1);        }    }    for(i=1;i<=n;i++){        for(j=1;j<=n;j++){            if(mp[i][j])continue;            a=(i-1)*n+j;            for(k=0;k<8;k++){                x=i+dis[k][0];                y=j+dis[k][1];                if(!yj(x,y)&&!mp[x][y]){                    b=(x-1)*n+y;                    add(a,b+n*n,1);                }            }        }    }    return s;}int main(){    int i,j,x,y,sum;    while(~scanf("%d%d",&n,&m))    {        init(); S=0; T=2*n*n+1;        memset(mp,0,sizeof(mp));        for(i=1;i<=m;i++){            scanf("%d%d",&x,&y);            mp[x][y]=1;        }        sum=build();        printf("%d\n",sum-sap(S,T,T+1)/2);    }    return 0;}




0 0
原创粉丝点击