您的位置:首页 > 其它

hdu(1569) 最大点权独立集

2011-08-21 21:09 253 查看
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1569

题意描述:

给你一个m*n的格子的棋盘,每个格子里面有一个非负数。

从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大
分析:该题求一个二分图的最大权独立集,那么如何建立二分图呢? 考虑到最大权独立集和最小点权覆盖集是互补的,那么我们就可以将该问题转化为最小点权覆盖了,从而转换为最小割问题! 下面给出两种建图的方法:

第一种:根据奇偶建立二分图,如果(i+j)%2==0 那么可以是该点和源点连接,其余的和汇点连接,权值均为该点的点权,之后若i+j为偶数的点和i+j为奇数的点之间相邻,那么就连一条从为偶数的点到为奇数的点的边,权值为无穷大

第二种: 拆点,将每个点权拆为两个点u',u‘’如果两个点相邻,那么连一条边从u‘到v’‘,权值为无穷大,u’连接源点,权值为点权,u‘’连接汇点,权值也为点权

代码如下:

ps: 加注释的为第一种建图方法,未加的为第二种建图方法

/*#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int inf = 0x3fffffff;
const int N = 2600;
const int E = 30000;

int e,head
;
int dep
,que
,cur
;
struct node
{
int x,y;
int nxt;
int c;
}edge[E];
void addedge(int u,int v,int c)
{
edge[e].x=u;
edge[e].y=v;
edge[e].nxt=head[u];
edge[e].c=c;
head[u]=e++;

edge[e].x=v;
edge[e].y=u;
edge[e].nxt=head[v];
edge[e].c=0;
head[v]=e++;
}

int maxflow(int s,int t)
{
int i,j,k,front,rear,top,min,res=0;
while(1)
{
memset(dep,-1,sizeof(dep));
front=0;
rear=0;
que[rear++]=s;
dep[s]=0;
while(front!=rear)
{
i=que[front++];
for(j=head[i];j!=-1;j=edge[j].nxt)
if(edge[j].c&&dep[edge[j].y]==-1)
{
dep[edge[j].y]=dep[i]+1;
que[rear++]=edge[j].y;

}
}
if(dep[t]==-1)
break;
memcpy(cur,head,sizeof(head));
for(i=s,top=0;;)
{
if(i==t)
{
min=inf;
for(k=0;k<top;k++)
if(min>edge[que[k]].c)
{
min=edge[que[k]].c;
front=k;
}
for(k=0;k<top;k++)
{
edge[que[k]].c-=min;
edge[que[k]^1].c+=min;
}
res+=min;
i=edge[que[top=front]].x;

}
for(j=cur[i];cur[i]!=-1;j=cur[i]=edge[cur[i]].nxt)
if(dep[edge[j].y]==dep[i]+1&&edge[j].c)
break;
if(cur[i]!=-1)
{
que[top++]=cur[i];
i=edge[cur[i]].y;
}
else
{
if(top==0)
break;
dep[i]=-1;
i=edge[que[--top]].x;
}
}
}
return res;
}
int main()
{
int n,m,i,j,c,sum;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));
e = 0;
int src = 0;
int sin = n*m+1;
sum = 0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%d",&c);
sum+=c;
if((i+j)%2 == 0)
{
addedge(src,(i-1)*m+j,c);
if(i>1)
addedge((i-1)*m+j,(i-2)*m+j,inf);
if(j>1)
addedge((i-1)*m+j,(i-1)*m+j-1,inf);
if(i<n)
addedge((i-1)*m+j,i*m+j,inf);
if(j<m)
addedge((i-1)*m+j,(i-1)*m+j+1,inf);
}
else addedge((i-1)*m+j,sin,c);

}
//    cout << sum <<endl;
printf("%d\n",sum-maxflow(src,sin));
}
return 0;
}
*/

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int N = 5100;
const int E = 80000;
const int inf = 0x3fffffff;

int e,head
;
int dep
,que
,cur
;

struct node
{
int x,y;
int nxt;
int c;
}edge[E];
void addedge(int u,int v,int c)
{
edge[e].x=u;
edge[e].y=v;
edge[e].nxt=head[u];
edge[e].c=c;
head[u]=e++;

edge[e].x=v;
edge[e].y=u;
edge[e].nxt=head[v];
edge[e].c=0;
head[v]=e++;
}

int maxflow(int s,int t)
{
int i,j,k,front,rear,top, min,res=0;
while(1)
{
memset(dep,-1,sizeof(dep));
front=0;
rear=0;
que[rear++]=s;
dep[s]=0;
while(front!=rear)
{
i=que[front++];
for(j=head[i];j!=-1;j=edge[j].nxt)
if(edge[j].c&&dep[edge[j].y]==-1)
{
dep[edge[j].y]=dep[i]+1;
que[rear++]=edge[j].y;

}
}
if(dep[t]==-1)
break;
memcpy(cur,head,sizeof(head));
for(i=s,top=0;;)
{
if(i==t)
{
min=inf;
for(k=0;k<top;k++)
if(min>edge[que[k]].c)
{
min=edge[que[k]].c;
front=k;
}
for(k=0;k<top;k++)
{
edge[que[k]].c-=min;
edge[que[k]^1].c+=min;
}
res+=min;
i=edge[que[top=front]].x;

}
for(j=cur[i];cur[i]!=-1;j=cur[i]=edge[cur[i]].nxt)
if(dep[edge[j].y]==dep[i]+1&&edge[j].c)
break;
if(cur[i]!=-1)
{
que[top++]=cur[i];
i=edge[cur[i]].y;
}
else
{
if(top==0)
break;
dep[i]=-1;
i=edge[que[--top]].x;
}
}
}
return res;
}
int main ()
{
int n, m,i,j;
int sum, c;
while(scanf("%d%d",&n,&m)!=EOF)
{
sum = 0;
int src = 0;
int sin = 2*n*m+1;
e =0;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf("%d",&c);
sum += c;
addedge(src,(i-1)*m+j,c);//建立源点到每个点的
addedge((i-1)*m+j+n*m,sin,c);
if(i>1)
addedge((i-1)*m+j,(i-2)*m+n*m+j,inf);
if(j>1)
addedge((i-1)*m+j, (i-1)*m+j-1+n*m,inf);
if(i<n)
addedge((i-1)*m+j,i*m+n*m+j,inf);
if(j<m)
addedge((i-1)*m+j,(i-1)*m+j+n*m+1,inf);
}
int flow = maxflow(src,sin);
printf("%d\n",sum-flow/2);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: