hdu4859 海岸线

best coder的题目,我没做,后来和曹圣一起做,然后问的zzb才会做的
首先对点进行黑白染色,相邻建边,流量为1
然后将所有的为d的点翻转颜色,这时候我们的最小割的定义就是最小化 相同的(陆地和陆地,海洋和海洋)之间的边的长度,
最小化了这个长度,那么总长度减去这个长度就是海岸线的长度,
考虑外围加一圈d

计算的时候注意一下就好了。。。

#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,lf?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]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]
        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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值