HDU 1565 方格取数(1)【网络流入门】

来源:互联网 发布:淘宝怎么提高店铺权重 编辑:程序博客网 时间:2024/06/09 08:20

题意不用说

我们将(i+j)%2==0的染黑,取余为1的染白,所有黑色不跟其他黑色相邻,白色也一样。将黑色的和源点组成一条边入图,白色和汇点组边入图,权值都为那个点的指。将黑色的相邻4个(都是白色)都加入图,权为INF,表示不相邻。然后网络流套入即可

最大点权独立集=总权-最小点权覆盖集

最小点权覆盖集 = 最小割 = 最大网络流

#include <cstdio>#include <cmath>#include <cstring>#include <set>#include <stack>#include <queue>#include <vector>#include <iostream>#include <algorithm>using namespace std;#define ll long long#define INF 0x7FFFFFFF#define INT_MIN -(1<<31)#define eps 10^(-6)#define Q_CIN ios::sync_with_stdio(false)#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )#define REV( i , n ) for ( int i = n - 1 ; i >= 0 ; -- i )#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define FOV( i , a , b ) for ( int i = a ; i >= b ; -- i )#define CLR( a , x ) memset ( a , x , sizeof (a) )#define RE freopen("in.txt","r",stdin)#define WE freopen("out.txt","w",stdout)#define NMAX 500#define min(a,b) ((a)>(b)?(b):(a))#define Dian_NAX 500int flow[Dian_NAX][Dian_NAX];   //边实际流量int cap[Dian_NAX][Dian_NAX];    //边容量int pre[NMAX];  //增广路径int res[NMAX];  //残余网络int n,m;int EK(int s,int t){    queue<int>q;    int ans = 0;    CLR(flow,0);    while(true)    {        CLR(res,0);        res[s] = INF; //源点无限大        q.push(s);        while(!q.empty())        {            int u = q.front();            q.pop();            for(int v=0;v<=m+1;v++)     //.......[0,n*n+1]                if(!res[v] && flow[u][v] < cap[u][v])                {                    pre[v] = u;                    q.push(v);                    res[v] = min(res[u],cap[u][v] - flow[u][v]);                }        }        if(res[t] == 0) //找不到增广路就退出            break;        for(int u = t;u != s; u = pre[u])        {            flow[pre[u]][u] += res[t];            flow[u][pre[u]] -= res[t];      //反向边        }        ans += res[t];    }    return ans;}int main(){    int pos,tmp;   // RE;    while(scanf("%d",&n)!=EOF)    {        CLR(cap,0);        int sum = 0;        int se = 0,et = n*n+1;      //源点和汇点不在原图里        m = n*n;        FOR(i,1,n)        {            FOR(j,1,n)            {                scanf("%d",&tmp);                sum += tmp;                pos = (i-1)*n+j;    //将数值下标排列到[1,n*n]                if((i+j)%2==0)                {                    cap[se][pos] = tmp;                    if(i!=1)                        cap[pos][pos-n] = INF;                    if(i!=n)                        cap[pos][pos+n] = INF;                    if(j!=1)                        cap[pos][pos-1] = INF;                    if(j!=n)                        cap[pos][pos+1] = INF;                }else                    cap[pos][et] = tmp;            }         }        int ans = EK(se,et);        printf("%d\n",sum-ans);    }    return 0;}


0 0