hdu 3657 Game 最小割

首先经典的奇偶建立二分图(X,Y),对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权,求最小割。

考虑一条路径 源->X->Y->汇

若割边选取的是源->X,则表示选Y点不选X点, 答案为w(X+Y)-w(X)

若割边选取的是Y->,则表示选X点不选Y点, 答案为w(X+Y)-w(Y)

若割边选取的是X->Y,则表示选Y点且选X点, 答案为w(X+Y)-w( 2*(X&Y) )

即总点权-最小割

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<string>
#define eps  1e-12
#define INF   0x7fffffff
#define maxn 22222
using namespace std;
int n,m,k;
int en;
int st,ed;	//源点和汇点
int dis[maxn] ;//dis[i],表示  到 原点  s 的 层数
int que[9999999];
struct edge
{
	int to,c,next;
};
edge e[9999999];
int head[maxn];
void add(int a,int b,int c)
{
	e[en].to=b;
	e[en].c=c;
	e[en].next=head[a];
	head[a]=en++;
	e[en].to=a;
	e[en].c=0;
	e[en].next=head[b];
	head[b]=en++;
}
int bfs()
{
    memset(dis,-1,sizeof(dis));
    dis[st]=0;
    int front=0,rear=0;
    que[rear++]=st;
    while(front<rear)
    {
        int j=que[front++];
        for(int k=head[j];k!=-1;k=e[k].next)
        {
            int i=e[k].to;
			if(dis[i]==-1&&e[k].c)
            {
                dis[i] = dis[j]+ 1 ;
                que[rear++]=i;
                if(i==ed) return true;
            }
        }
    }
    return false;
}
int dfs(int x,int mx)
{
    int i,a;
    if(x==ed) return mx ;
    int ret=0;
    for(int k=head[x];k!=-1&&ret<mx;k=e[k].next)
    {
        if(e[k].c&&dis[e[k].to]==dis[x]+1)
        {
            int dd=dfs(e[k].to,min(e[k].c,mx-ret));
            e[k].c-=dd;
            e[k^1].c+=dd;
            ret+=dd;
        }
    }
    if(!ret) dis[x]=-1;
    return ret;
}
bool vis[100][100];
void init()
{
    en=0;
	st=0;     //源
    ed=n*m+1;     //汇
	memset(head,-1,sizeof(head));
	memset(vis,0,sizeof(vis));
}
int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
int a[100][100];
int id[100][100];

int ans;
void build()
{
    int x,y,z;
    ans=0;
    for(int i=1,cnt=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
            ans+=a[i][j];
            id[i][j]=cnt++;
        }
    }
    for(int i=1;i<=k;i++)
    {
        scanf("%d%d",&x,&y);
        if(x%2==y%2) add(st,id[x][y],INF);
        else add(id[x][y],ed,INF);
        vis[x][y]=1;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(i%2==j%2){
            for(int d=0;d<4;d++)
            {
                int ii=i+dx[d];
                int jj=j+dy[d];
                if(ii>=1&&ii<=n&&jj>=1&&jj<=m)
                {
                    add(id[i][j],id[ii][jj],2*(a[i][j]&a[ii][jj]));
                }
            }
            if(!vis[i][j]) add(st,id[i][j],a[i][j]);
            }
            else if(!vis[i][j]) add(id[i][j],ed,a[i][j]);
        }
    }
}
int dinic()
{
    int tmp=0;
    int maxflow=0;
    while(bfs())
    {
        while(tmp=dfs(st,INF)) maxflow+=tmp;
    }
    return maxflow;
}
int main()
{
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        init();
        build();
        printf("%d\n",ans-dinic());
    }
}
时间: 2024-10-12 02:58:15

hdu 3657 Game 最小割的相关文章

HDU 4859 海岸线 最小割

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4859 题解: 这题考察的是最小割. 我们可以这样想:海岸线的长短变化都是E引起的,我们通过把’E'变成'.'或'D'来使海岸线最大化. 我们要算海岸线就是算格子‘.'和格子'D'(在原有地图周围四面都要加’D‘)相邻的面数,要使它最大,就是要使'.'与’.':'D'与'D'相邻的面数最小,而面数最小可以用最小割来做. 现在我们先把格子上的点黑白染色,(i+j)%2==1的为A类,为0的为B类, 在

HDU 3061 Battle(最小割----最大权闭合图)

题目地址:HDU 3061 多校中遇到的最小割的最大权闭合模型花了一上午时间终于看懂啦. 最大权闭合图就是将一些互相有依赖关系的点转换成图,闭合图指的是在图中的每一个点的后继点都是在图内的. 还要明白简单割的概念,就是指所有的割边都与源点或汇点相连.然后让源点与正权点相连,汇点与负权点相连,权值均为其绝对值,有依赖关系的点连一条有向边,如果a必须在b的基础上,那么就连一条a->b的有向边,权值为INF.最后用所有正权值得和减去最小割的值就是答案. 具体证明可看胡伯涛大牛的国家队集训论文<最小割

hdu 3987 求最小割条数最小

题意:    一个人要从起点  0  到达 n-1   n个点  m条路  ,我们求最少破坏路的条数使无法 从起点到达终点.题意很明显  ,求最小割条数最少,由于最小割流量虽然固定,但是其条数却不固定,可以破坏3条路,也可以破坏4条路,他们总流量相同才会出现这种情况. 题解:由于上述的情况,他们总流量相同但是条数不同,现在我们需要改变边的容量使得条数少边才是最小割,条数多的将不会是最小割. 官方题解有两种 ,我选择的是在残余网络中进行扩充流的操作,使的两个最小割不同,残余网络中,我进行所有边流量

HDU - 4289 Control (最小割 MCMF)

题目大意:有一个间谍要将一些机密文件送到目的地 现在给出间谍的初始位置和要去的目的地,要求你在间谍的必经路上将其拦获且费用最小 解题思路:最小割最大流的应用,具体可以看网络流–最小割最大流 建图的话 超级源点–起始城市,容量为INF 城市拆成两点(u, v),容量为监视该城市的代价 能连通的城市连接,容量为INF 目的地和超级汇点相连,容量为INF #include <cstdio> #include <cstring> #include <algorithm> #in

HDU 3046【最小割】

题目大意:在一个n*m的矩阵上,1代表羊,2代表狼,0代表平地,我们有长度为1的一个栅栏(不是放在格子上的,是放在格子和格子之间的空隙上的),问使用最少的栅栏,能够使得狼吃不到羊. 又学到了一招,以前一直以为建图是要先设好S点T点,在把其他的点和他们两一一相连.今天学到了原来可以在整个map上根据条件建好图,再把其中的某些目标点和源汇点相连的. 思路如下: 1.建立最小割模型: ①建立源点S,将源点S连入各个有狼的节点上,权值设定为INF,表示狼可以从任意方向出发. ②建立汇点T,将各个羊节点连

HDU 4289 Control 最小割

Control 题意:有一个犯罪集团要贩卖大规模杀伤武器,从s城运输到t城,现在你是一个特殊部门的长官,可以在城市中布置眼线,但是布施眼线需要花钱,现在问至少要花费多少能使得你及时阻止他们的运输. 题解:裸的最小割模型,最小割就是最大流,我们把点拆成2个点,然后将原点与拆点建边,流量为在城市建立眼线的费用,然后拆点为出点,原点为入点,将可以到达的城市之间建流量为无穷的边. 最后求出s 到 t的拆点的最大流 那么就是这个题目的答案了. 代码: 1 #include<bits/stdc++.h>

Golden Eggs HDU - 3820(最小割)

Golden Eggs Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 673    Accepted Submission(s): 400 Problem Description There is a grid with N rows and M columns. In each cell you can choose to put a

HDU 4307 Matrix 最小割 矩阵乘法展开

==线代好难 #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> #include<algorithm> #include<queue> #include<vector> template <class T> inline bool rd(T &ret) { char c; int sgn; if(c=getc

HDU 5889【最小割+最短路】

题意:给出一张n个点m条边的无向图,边权均为1,敌人在n点准备走最短路在攻击己方位置1点,现在要在一些边上设置一些路障,给出每条边设置路障的代价,要求用最少的代价设置路障使得敌人必然遇到路障. 这份代码了用到了当前弧优化,尽管我不是很懂... 但素不用的话会超时! #include<stdio.h> #include<string.h> #include<queue> using namespace std; struct node { int from; int to