最大流最小割(最大点权独立集)

来源:互联网 发布:手机如何开淘宝店视频 编辑:程序博客网 时间:2024/05/03 04:05

hdu3657

Game

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 832    Accepted Submission(s): 351


Problem Description
onmylove has invented a game on n × m grids. There is one positive integer on each grid. Now you can take the numbers from the grids to make your final score as high as possible. The way to get score is like
the following:
● At the beginning, the score is 0;
● If you take a number which equals to x, the score increase x;
● If there appears two neighboring empty grids after you taken the number, then the score should be decreased by 2(x&y). Here x and y are the values used to existed on these two grids. Please pay attention that "neighboring grids" means there exits and only exits one common border between these two grids.

Since onmylove thinks this problem is too easy, he adds one more rule:
● Before you start the game, you are given some positions and the numbers on these positions must be taken away.
Can you help onmylove to calculate: what's the highest score onmylove can get in the game?
 

Input
Multiple input cases. For each case, there are three integers n, m, k in a line.
n and m describing the size of the grids is n ×m. k means there are k positions of which you must take their numbers. Then following n lines, each contains m numbers, representing the numbers on the n×m grids.Then k lines follow. Each line contains two integers, representing the row and column of one position
and you must take the number on this position. Also, the rows and columns are counted start from 1.
Limits: 1 ≤ n, m ≤ 50, 0 ≤ k ≤ n × m, the integer in every gird is not more than 1000.
 

Output
For each test case, output the highest score on one line.
 

Sample Input
2 2 12 22 21 12 2 12 74 11 1
 

Sample Output
49
Hint
As to the second case in Sample Input, onmylove gan get the highest score when calulating like this:2 + 7 + 4 - 2 × (2&4) - 2 × (2&7) = 13 - 2 × 0 - 2 × 2 = 9.

【题意】

给出一个n*m的格子,格子里有分数,取出得到相应的分数,若取出后导致相邻的格子都为0分,则应减去2*(score1 & score2),附加了某些格子是必须被选择的。求能得到的最大分数。

【思路】

建图:把i+j为偶数作为左边节点,为奇数作为右边节点,设超级源点和汇点source、sink,source连接左边节点,流量为格子的分数;右边节点连接sink,流量为格子的分数;对于必须选择的格子,只需把流量修改为inf,如左边节点与右边节点相邻,则连边,流量为2*(score1 & score2)。求最小点权覆盖集=最小割=最大流。最后结果等于所有格子分数总和 - 最小点权覆盖集大小。


分析:

把图按照横纵坐标和的奇数偶数划分成二分图,建立源点和汇点,源点和奇数相连,权值为其点权值,偶数和汇点相连,权值也为点权值,把图中相邻的点相连,权值为2*(a&b),把必须要选取的点和源点或者汇点相连,权值为inf,表示不会割掉这条边;

程序:

#include"stdio.h"#include"string.h"#define M 100005#define inf 999999999int min(int a,int b){    return a<b?a:b;}struct st{    int u,v,next,w;}edge[M];int head[M],work[M],q[M],dis[M],t;void init(){    t=0;    memset(head,-1,sizeof(head));}void add(int u,int v,int w){    edge[t].u=u;    edge[t].v=v;    edge[t].w=w;    edge[t].next=head[u];    head[u]=t++;    edge[t].u=v;    edge[t].v=u;    edge[t].w=0;    edge[t].next=head[v];    head[v]=t++;}int bfs(int S,int T){    int rear=0;    memset(dis,-1,sizeof(dis));    dis[S]=0;    q[rear++]=S;    for(int i=0;i<rear;i++)    {        for(int j=head[q[i]];j!=-1;j=edge[j].next)        {            int v=edge[j].v;            if(edge[j].w&&dis[v]==-1)            {                dis[v]=dis[q[i]]+1;                q[rear++]=v;                if(v==T)                    return 1;            }        }    }    return 0;}int dfs(int S,int a,int T){    if(S==T)        return a;    for(int &i=work[S];i!=-1;i=edge[i].next)    {        int v=edge[i].v;        if(edge[i].w&&dis[v]==dis[S]+1)        {            int tt=dfs(v,min(a,edge[i].w),T);            if(tt)            {                edge[i].w-=tt;                edge[i^1].w+=tt;                return tt;            }        }    }    return 0;}int Dinic(int S,int T){    int ans=0;    while(bfs(S,T))    {        memcpy(work,head,sizeof(head));        while(int tt=dfs(S,inf,T))            ans+=tt;    }    return ans;}int main(){    int n,m,i,j,k,mp[55][55],use[55][55];    while(scanf("%d%d%d",&n,&m,&k)!=-1)    {        int sum=0;        memset(use,0,sizeof(use));        for(i=0;i<n;i++)        {            for(j=1;j<=m;j++)            {                scanf("%d",&mp[i][j]);                sum+=mp[i][j];            }        }        for(i=1;i<=k;i++)        {            int a,b;            scanf("%d%d",&a,&b);            a--;            use[a][b]=1;        }        init();        for(i=0;i<n;i++)        {            for(j=1;j<=m;j++)            {                if((i+j)&1)                {                    if(use[i][j])                        add(0,i*m+j,inf);                    add(0,i*m+j,mp[i][j]);                    if(j+1<=m)                        add(i*m+j,i*m+j+1,2*(mp[i][j]&mp[i][j+1]));                    if(i+1<n)                        add(i*m+j,(i+1)*m+j,2*(mp[i][j]&mp[i+1][j]));                }                else                {                    if(use[i][j])                        add(i*m+j,m*n+1,inf);                    add(i*m+j,m*n+1,mp[i][j]);                    if(j+1<=m)                        add(i*m+j+1,i*m+j,2*(mp[i][j]&mp[i][j+1]));                    if(i+1<n)                        add((i+1)*m+j,i*m+j,2*(mp[i][j]&mp[i+1][j]));                }            }        }        //for(i=0;i<t;i+=2)            //printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);        int ans=Dinic(0,m*n+1);        printf("%d\n",sum-ans);    }}


0 0
原创粉丝点击