[HDOJ 4859] 海岸线 [最大流]

来源:互联网 发布:matlab编程语言 编辑:程序博客网 时间:2024/05/10 21:41

听别人说的..还没太想明白...

首先把图扩大一圈,放上'D',即海,图中相邻的点连边。

然后将图黑白染色,像国际象棋棋盘一样。

如果这时将源向黑格连边,白格向汇连边,若这个格为E则不连,求最大流得到的是海岸线的长度的最小值。

现在将标为D的格的颜色反转,然后再源向黑格连边,白格向汇连边,若这个格为E则不连,得到的就是不是海岸线的位置的个数的最小值,然后用总的条数减去即可。

#include<cstdio>#include<cstring>#include<cstdlib>int caseTest;const long long MAXINT=(1ll<<60);const int N=5010;const int M=30010;struct NetWorkFlow {    struct Edge {        int t;        long long f;        Edge *ne,*p;        Edge () {}        Edge (int tt,int ff,Edge *nee) {            t=tt;f=ff;ne=nee;        }        void *operator new(size_t,void *p) {            return p;        }    };    Edge b[M*2];    Edge *p,*fe[N],*cur[N];    int n,s,t;    int h[N],vh[N];    void clear(int nn,int ss,int tt) {        n=nn;s=ss;t=tt;        for (int i=0;i<=n;i++) fe[i]=NULL;        p=b;    }    void putedge(int x,int y,int f) {        //printf("%d %d %d\n",x,y,f);        fe[x]=new(p++)Edge(y,f,fe[x]);        fe[y]=new(p++)Edge(x,0,fe[y]);        fe[x]->p=fe[y];        fe[y]->p=fe[x];    }    long long aug(int i,long long f) {        if (i==t) return f;        long long l=f;        for (Edge *&j=cur[i];j;j=j->ne) {            if (j->f&&h[j->t]+1==h[i]) {                long long tmp=aug(j->t,l<j->f?l:j->f);                j->f-=tmp;                j->p->f+=tmp;                l-=tmp;                if (h[s]==n||!l) return f-l;            }        }        int minh=n-1;        for (Edge *j=cur[i]=fe[i];j;j=j->ne) {            if (j->f&&h[j->t]<minh) minh=h[j->t];        }        minh++;        if (!--vh[h[i]]) h[s]=n;        else ++vh[h[i]=minh];        return f-l;    }    long long flow() {        long long ans=0;        vh[0]=n;        for (int i=0;i<=n;i++) {            cur[i]=fe[i];            h[i]=vh[i]=0;        }        while (h[s]<n) ans+=aug(s,MAXINT);        return ans;    }};NetWorkFlow c;int n,m;char str[100][100];int color[100][100];int calc(int i , int j){    return ( i * ( m + 1 ) + j )+1;}int main() {    scanf("%d",&caseTest);    for (int cas = 1; cas <= caseTest ; cas++)    {        int i,x,y,z;        scanf("%d%d",&n,&m);        int sta = (n+2)*(m+2)+1;        int edt = sta+1;        c.clear(edt,sta,edt);//点个数 s t        for (int i = 1; i <= n ; i ++)            for (int j = 1; j <= m ; j ++)                scanf(" %c",&str[i][j]);        for (int i = 0; i <= n+1 ; i ++)        {            str[i][0] = str[i][m+1]='D';        }//处理边上一圈                for (int i = 0; i <= m+1 ; i ++)        {            str[0][i] = str[n+1][i]='D';        }//处理边上一圈        n++;m++;        for (int i = 0 ; i <= n ; i ++)        {            for (int j = 0 ; j <= m ; j++)            {                color[i][j] = ((i + j) & 1);            }        }//黑白染色        for (int i = 1; i < n ; i ++)        for (int j = 1; j < m ; j ++)        {            c.putedge(calc(i,j),calc(i,j+1),1);            c.putedge(calc(i,j),calc(i,j-1),1);            c.putedge(calc(i,j),calc(i-1,j),1);            c.putedge(calc(i,j),calc(i+1,j),1);        }//相邻建边        for (int i = 1 ; i < n ; i++)        {            c.putedge(calc(i,0),calc(i,1),1);            c.putedge(calc(i,0),calc(i-1,0),1);            c.putedge(calc(i,0),calc(i+1,0),1);            c.putedge(calc(i,m),calc(i,m-1),1);            c.putedge(calc(i,m),calc(i-1,m),1);            c.putedge(calc(i,m),calc(i+1,m),1);        }//处理左右边界        for (int j = 1 ; j < m ; j++)        {            c.putedge(calc(0,j),calc(1,j),1);            c.putedge(calc(0,j),calc(0,j-1),1);            c.putedge(calc(0,j),calc(0,j+1),1);            c.putedge(calc(n,j),calc(n-1,j),1);            c.putedge(calc(n,j),calc(n,j-1),1);            c.putedge(calc(n,j),calc(n,j+1),1);        }//处理上下边界        c.putedge(calc(0,0),calc(0,1),1);        c.putedge(calc(0,0),calc(1,0),1);        c.putedge(calc(n,0),calc(n,1),1);                c.putedge(calc(n,0),calc(n-1,0),1);        c.putedge(calc(n,m),calc(n-1,m),1);        c.putedge(calc(n,m),calc(n,m-1),1);        c.putedge(calc(0,m),calc(0,m-1),1);        c.putedge(calc(0,m),calc(1,m),1);        //处理四个角的点        for (int i = 0 ; i <= n ; i ++)        {            for (int j = 0 ; j <= m ; j++)            {                if (str[i][j]=='D') color[i][j] ^= 1;            }        }        //颜色翻转        for (int i = 0 ; i <= n ; i++)        {            for (int j = 0 ; j <= m ; j ++)            {                if (str[i][j]=='E') continue;                if (color[i][j]) c.putedge(sta,calc(i,j),100);                else c.putedge(calc(i,j),edt,100);            }        }//建立源汇边        long long tmp=c.flow();        //printf("Case %d maxflow: %lld\n",cas,tmp);        printf("Case %d: %lld\n",cas,(n+1)*m+(m+1)*n-tmp);    }    return 0;}


0 0