hdu 1565 方格取数 最大点权独立集

方格取数(1)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6094    Accepted Submission(s): 2330


Problem Description
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
 

 

Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)
 

 

Output
对于每个测试实例,输出可能取得的最大的和
 

 

Sample Input
3 75 15 21 75 15 28 34 70 5
 

 

Sample Output
188
 
 
纯粹的最大点权独立集,适合初学者
#include<iostream>

#include<queue>

#include<cstring>

#include<cstdio>

#include<climits>

#define MAXE 2000

#define MAXP 410

#define Max(a,b) a>b?a:b

#define Min(a,b) a<b?a:b

using namespace std;

struct Edge

{

    int s,t,f,next;

}edge[MAXE];

int head[MAXP];

int cur[MAXP];

int pre[MAXP];

int stack[MAXE];

int ent;

int sum;

int n,m,s,t;

int num;

void add(int start,int last,int f)

{

    edge[ent].s=start;edge[ent].t=last;edge[ent].f=f;edge[ent].next=head[start];head[start]=ent++;

    edge[ent].s=last;edge[ent].t=start;edge[ent].f=0;edge[ent].next=head[last];head[last]=ent++;

}

bool bfs(int S,int T)

{

    memset(pre,-1,sizeof(pre));

    pre[S]=0;

    queue<int>q;

    q.push(S);

    while(!q.empty())

    {

        int temp=q.front();

        q.pop();

        for(int i=head[temp];i!=-1;i=edge[i].next)

        {

            int temp2=edge[i].t;

            if(pre[temp2]==-1&&edge[i].f)

            {

                pre[temp2]=pre[temp]+1;

                q.push(temp2);

            }

        }

    }

    return pre[T]!=-1;

}

int dinic(int start,int last)

{

    int flow=0,now;

    while(bfs(start,last))

    {

        int top=0;

        memcpy(cur,head,sizeof(head));

        int u=start;

        while(1)

        {

            if(u==last)//如果找到终点结束对中间路径进行处理并计算出该流

            {

                int minn=INT_MAX;

                for(int i=0;i<top;i++)

                {

                    if(minn>edge[stack[i]].f)

                    {

                        minn=edge[stack[i]].f;

                        now=i;

                    }

                }

                flow+=minn;

                for(int i=0;i<top;i++)

                {

                    edge[stack[i]].f-=minn;

                    edge[stack[i]^1].f+=minn;

                }

                top=now;

                u=edge[stack[top]].s;

            }

            for(int i=cur[u];i!=-1;cur[u]=i=edge[i].next)//找出从u点出发能到的边

                if(edge[i].f&&pre[edge[i].t]==pre[u]+1)

                    break;

            if(cur[u]==-1)//如果从该点未找到可行边,将该点标记并回溯

            {

                if(top==0)break;

                pre[u]=-1;

                u=edge[stack[--top]].s;

            }

            else//如果找到了继续运行

            {

                stack[top++]=cur[u];

                u=edge[cur[u]].t;

            }

        }

    }

    return flow;

}

int main()

{

    while(~scanf("%d",&n))

    {

        s=0;t=n*n+1;

        sum=0;

        memset(head,-1,sizeof(head));

        ent=0;

        for(int i=0;i<n;i++)

        {

            for(int j=0;j<n;j++)

            {

                scanf("%d",&num);

                sum+=num;

                if((i+j)%2)

                {

                    add(i*n+j+1,t,num);

                }

                else

                {

                    add(s,i*n+j+1,num);

                    if(i!=0)

                        add(i*n+j+1,(i-1)*n+j+1,INT_MAX);

                    if(j!=0)

                        add(i*n+j+1,i*n+j,INT_MAX);

                    if(i!=n-1)

                        add(i*n+j+1,(i+1)*n+j+1,INT_MAX);

                    if(j!=n-1)

                        add(i*n+j+1,i*n+j+2,INT_MAX);

                }

            }

        }

        printf("%d\n",sum-dinic(s,t));

    }

    return 0;

}

 

你可能感兴趣的:(HDU)