hdu 4859 最大点权独立集的变形(方格取数的变形)

来源:互联网 发布:java 继承 构造函数 编辑:程序博客网 时间:2024/06/05 08:18
/*刚开始不会写,最大点权独立集神马都不知道,在潘神的指导下终于做出来,灰常感谢ps;和方格取数差不多奇偶建图,对于D必割点权为0,对于.必然不割点权为inf。然后和方格取数差不多的建图.--.||E权值为2,,.||E--D权值为0.最大点权独立集=sum-最小点权覆盖。*/#include<stdio.h>#include<string.h>#include<queue>using namespace std;#define inf 0x3fffffff#define ii 50#define N   3000struct node { int u,v,w,next;}bian[N*6];int head[N],yong,s,t,dis[N];void init(){yong=0;memset(head,-1,sizeof(head));memset(dis,-1,sizeof(dis));}void addedge(int u,int v,int w) {bian[yong].u=u;bian[yong].v=v;bian[yong].w=w;bian[yong].next=head[u];head[u]=yong++;}void add(int u,int v,int w) { addedge(u,v,w); addedge(v,u,0);}void bfs() {int u,v,i;queue<int>q;q.push(t);dis[t]=0;while(!q.empty()) {    u=q.front();    q.pop();    for(i=head[u];i!=-1;i=bian[i].next) {        v=bian[i].v;        if(dis[v]==-1) {            dis[v]=dis[u]+1;            q.push(v);        }    }}return ;}int ISAP() {int sum=0;bfs();int  gap[N],cur[N],stac[N],top,i;memset(gap,0,sizeof(gap));for(i=s;i<=t;i++) {    gap[dis[i]]++;    cur[i]=head[i];}int k=s;top=0;while(dis[s]<t+1) {     if(k==t) {            int minn=inf,index;        for(i=0;i<top;i++) {            int e=stac[i];            if(minn>bian[e].w) {                minn=bian[e].w;                index=i;            }        }        for(i=0;i<top;i++) {            int e=stac[i];            bian[e].w-=minn;            bian[e^1].w+=minn;        }        sum+=minn;        top=index;        k=bian[stac[top]].u;     }     for(i=cur[k];i!=-1;i=bian[i].next) {       int  v=bian[i].v;        if(bian[i].w&&dis[k]==dis[v]+1) {            cur[k]=i;            k=v;            stac[top++]=i;            break;        }     }     if(i==-1) {        int m=t+1;        for(i=head[k];i!=-1;i=bian[i].next)            if(m>dis[bian[i].v]&&bian[i].w) {                m=dis[bian[i].v];                cur[k]=i;            }            if(--gap[dis[k]]==0)break;            gap[dis[k]=m+1]++;            if(k!=s)                k=bian[stac[--top]].u;     }}return sum;}int main() {    int n,m,i,j,T,id[ii][ii],cnt,sum,f=0;    char ss[ii][ii];    scanf("%d",&T);    while(T--){        scanf("%d%d",&n,&m);        cnt=1;sum=0;        init();        for(i=1;i<=n;i++) {            scanf("%s",ss[i]+1);            for(j=1;j<=m;j++) {                if(ss[i][j]=='.'||ss[i][j]=='E')//记录总数                    sum+=4;                id[i][j]=cnt++;            }        }        s=0;t=n*m+1;        for(i=1;i<=n;i++)        for(j=1;j<=m;j++) {            if((i+j)&1) {//奇偶建图与源点相连                if(ss[i][j]=='.')                    add(s,id[i][j],inf);//必然不割                if(ss[i][j]=='D')//必割                    add(s,id[i][j],0);                if(ss[i][j]=='E')//任意选择                    add(s,id[i][j],4);                if(i>=2) {                    if(ss[i][j]=='.'||ss[i][j]=='E') {                        if(ss[i-1][j]=='.'||ss[i-1][j]=='E')add(id[i][j],id[i-1][j],2);//                        if(ss[i-1][j]=='D')add(id[i][j],id[i-1][j],0);//                    }                    else                        add(id[i][j],id[i-1][j],0);                }                if(j>=2) {                   if(ss[i][j]=='.'||ss[i][j]=='E') {                        if(ss[i][j-1]=='.'||ss[i][j-1]=='E')add(id[i][j],id[i][j-1],2);                        if(ss[i][j-1]=='D')add(id[i][j],id[i][j-1],0);                    }                    else                        add(id[i][j],id[i][j-1],0);                }                if(i<=n-1){                     if(ss[i][j]=='.'||ss[i][j]=='E') {                        if(ss[i+1][j]=='.'||ss[i+1][j]=='E')add(id[i][j],id[i+1][j],2);                        if(ss[i+1][j]=='D')add(id[i][j],id[i+1][j],0);                    }                    else                        add(id[i][j],id[i+1][j],0);                }                if(j<=m-1) {                      if(ss[i][j]=='.'||ss[i][j]=='E') {                        if(ss[i][j+1]=='.'||ss[i][j+1]=='E')add(id[i][j],id[i][j+1],2);                        if(ss[i][j+1]=='D')add(id[i][j],id[i][j+1],0);                        }                    else                        add(id[i][j],id[i][j+1],0);                }            }            else {//与汇点相连                if(ss[i][j]=='.')                    add(id[i][j],t,inf);                if(ss[i][j]=='E')                    add(id[i][j],t,4);                if(ss[i][j]=='D')                    add(id[i][j],t,0);            }        }        printf("Case %d: ",++f);        printf("%d\n",sum-ISAP());    }return 0;}

0 0